Как обнаружить, если функция вызвана как конструктор?

MySQL: У вас есть ошибка в синтаксисе SQL; проверьте руководство, соответствующее вашей версии сервера MySQL, для правильного синтаксиса для использования рядом с ... at line ...

Эта ошибка часто возникает из-за того, что вы забыли правильно удалить данные, переданные в MySQL-запрос .

Пример того, что не делать («Плохая идея»):

$query = "UPDATE `posts` SET my_text='{$_POST['text']}' WHERE id={$_GET['id']}";
mysqli_query($db, $query);

Этот код может быть включен в страницу с формой для отправки с URL-адресом например http://example.com/edit.php?id=10 (для редактирования сообщения n ° 10)

Что произойдет, если представленный текст содержит одинарные кавычки ? $query закончится:

$query = "UPDATE `posts` SET my_text='I'm a PHP newbie' WHERE id=10';

И когда этот запрос будет отправлен в MySQL, он будет жаловаться, что синтаксис неверен, потому что в середине есть отдельная одинарная кавычка.

Чтобы избежать таких ошибок, вы ДОЛЖНЫ всегда избегать данных перед использованием в запросе.

Экранирование данных перед использованием в SQL-запросе также очень важно, потому что если вы этого не сделаете, ваш скрипт будет быть открытым для инъекций SQL. SQL-инъекция может привести к изменению, потере или изменению записи, таблицы или всей базы данных. Это серьезная проблема безопасности!

Документация:

104
задан alex 17 August 2011 в 12:06
поделиться

8 ответов

ПРИМЕЧАНИЕ. Теперь это возможно в ES2015 и более поздних версиях. См. ответ Дэниела Вайнера .

Я не думаю, что то, что вы хотите, возможно [до ES2015]. В функции просто недостаточно информации, чтобы сделать надежный вывод.

Если посмотреть на спецификацию 3-го издания ECMAScript, шаги, предпринимаемые при вызове new x () , по существу:

  • Создайте новый объект
  • Назначьте его внутреннее свойство [[Prototype]] свойству прототипа x
  • Вызовите x как обычно, передав ему новый объект как this
  • Если вызов x вернул объект, верните его, в противном случае верните новый объект

Ничего полезного в том, как была вызвана функция, не становится доступным для исполняемого кода, так что единственное, что это ' s можно проверить внутри x - это значение this , что и делают все ответы здесь. Как вы заметили, новый экземпляр * x при вызове x в качестве конструктора неотличим от ранее существовавшего экземпляра x , переданного как ] this при вызове x как функции, , если вы не назначаете свойство каждому новому объекту, созданному с помощью x по мере его создания:

function x(y) {
    var isConstructor = false;
    if (this instanceof x // <- You could use arguments.callee instead of x here,
                          // except in in EcmaScript 5 strict mode.
            && !this.__previouslyConstructedByX) {
        isConstructor = true;
        this.__previouslyConstructedByX = true;
    }
    alert(isConstructor);
}

Очевидно, это не идеально, поскольку теперь у вас есть дополнительное бесполезное свойство для каждого объекта, построенного с помощью x , которое можно перезаписать, но я думаю, что это лучшее, что вы можете сделать.

(*) "instance of" - неточный термин, но он достаточно близок и более краток, чем "

88
ответ дан 24 November 2019 в 04:07
поделиться

Два пути, по существу то же под капотом. Можно протестировать то, что объем this, или можно протестировать, какой this.constructor.

, Если Вы назвали метод, поскольку конструктор this будет новым экземпляром класса, если Вы назовете метод, поскольку метод this будет объектом контекста методов. Так же конструктор объекта будет самим методом, если названо как новым, и конструктор системного объекта иначе. Это ясно как грязь, но это должно помочь:

var a = {};

a.foo = function () 
{
  if(this==a) //'a' because the context of foo is the parent 'a'
  {
    //method call
  }
  else
  {
    //constructor call
  }
}

var bar = function () 
{
  if(this==window) //and 'window' is the default context here
  {
    //method call
  }
  else
  {
    //constructor call
  }
}

a.baz = function ()
{
  if(this.constructor==a.baz); //or whatever chain you need to reference this method
  {
    //constructor call
  }
  else
  {
    //method call
  }
}
8
ответ дан annakata 24 November 2019 в 04:07
поделиться

ПРИМЕЧАНИЕ: Этот ответ был записан в [1 114] 2008 , когда JavaScript был все еще в [1 115] ES3 от [1 116] 1999 . Большая новая функциональность была добавлена с тех пор, поэтому теперь лучшие решения существуют. Этот ответ сохранен по историческим причинам.

преимущество кода ниже - то, что Вы не должны определять название функции дважды, и это работает на анонимные функции также.

function x() {
    if ( (this instanceof arguments.callee) ) {
      alert("called as constructor");
    } else {
      alert("called as function");
    }
}

Обновление Как claudiu указал в комментарии ниже, вышеупомянутый код не работает при присвоении конструктора тому же объекту, это создало. Я никогда не писал код, который делает это и имеет более новый замеченный кто-либо еще сделать это eighter.

пример Claudius:

var Z = new x();
Z.lolol = x;
Z.lolol();

Путем добавления свойства к объекту, возможно обнаружить, если объект был инициализирован.

function x() {
    if ( (this instanceof arguments.callee && !this.hasOwnProperty("__ClaudiusCornerCase")) ) {
        this.__ClaudiusCornerCase=1;
        alert("called as constructor");
    } else {
        alert("called as function");
    }
}

Даже код выше повредится при удалении добавленного свойства. можно однако перезаписать его с любым значением, которое Вы любите, включая undefined, и это все еще работает. , Но если Вы удаляете его, это повредится.

нет в это время никакой собственной поддержки в ecmascript для обнаружения, если функция была вызвана как конструктор. Это - самая близкая вещь, которую я придумал до сих пор, и она должна работать, если Вы не удаляете свойство.

19
ответ дан some 24 November 2019 в 04:07
поделиться

1) можно проверить this.constructor:

function x(y)
{
    if (this.constructor == x)
        alert('called with new');
    else
         alert('called as function');
}

2) Да, возвращаемое значение просто отбрасывается, когда используется в new контекст

52
ответ дан TheHippo 24 November 2019 в 04:07
поделиться

В моем тестировании для http://packagesinjavascript.wordpress.com/ я обнаружил, что тест if (this == window) должен работать в разных браузерах во всех случаях , так что я использовал именно его.

-Stijn

2
ответ дан 24 November 2019 в 04:07
поделиться

Используйте этот экземпляр arguments.callee (при желании заменив arguments.callee функцией, в которой он находится, что повышает производительность), чтобы проверить, вызывается ли что-то как конструктор. Не используйте this.constructor , так как его можно легко изменить.

0
ответ дан 24 November 2019 в 04:07
поделиться

Тим Даун, я думаю, прав. Я думаю, что как только вы дойдете до того момента, когда, по вашему мнению, вам нужно уметь различать два режима вызова, вам не следует использовать ключевое слово « this ». this ненадежен, и это может быть глобальный объект, или это может быть какой-то совершенно другой объект. Дело в том, что иметь функцию с этими различными режимами активации, некоторые из которых работают так, как вы предполагали, а другие делают что-то совершенно дикое, нежелательно. Я думаю, что, возможно, вы пытаетесь понять это из-за этого.

Существует идиоматический способ создать функцию-конструктор, которая ведет себя одинаково независимо от того, как она вызывается. будь то Thing (), new Thing () или foo.Thing (). Это выглядит так:

function Thing () {
   var that = Object.create(Thing.prototype);
   that.foo="bar";
   that.bar="baz";
   return that;
}

где Object. create - это новый стандартный метод ecmascript 5, который может быть реализован в обычном javascript следующим образом:

if(!Object.create) {
    Object.create = function(Function){
        // WebReflection Revision
       return function(Object){
           Function.prototype = Object;
           return new Function;
    }}(function(){});
}

Object.create принимает объект в качестве параметра и возвращает новый объект с переданным объектом в качестве его прототипа.

Однако если вы действительно пытаетесь заставить функцию вести себя по-разному в зависимости от того, как она вызывается, значит, вы плохой человек и вам не следует писать код javascript.

0
ответ дан 24 November 2019 в 04:07
поделиться

Расширение решения Gregs, оно отлично работает с предоставленными вами тестовыми примерами:

function x(y) {
    if( this.constructor == arguments.callee && !this._constructed ) {
        this._constructed = true;
        alert('called with new');
    } else {
        alert('called as function');
    }
}

РЕДАКТИРОВАТЬ: добавление некоторых тестовых примеров

x(4);             // OK, function
var X = new x(4); // OK, new

var Z = new x();  // OK, new
Z.lolol = x; 
Z.lolol();        // OK, function

var Y = x;
Y();              // OK, function
var y = new Y();  // OK, new
y.lolol = Y;
y.lolol();        // OK, function
3
ответ дан 24 November 2019 в 04:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: