javascript - это - prototype js




Легитимное использование конструктора Function (5)

jQuery использует его для разбора строк JSON, когда объект парсера JSON недоступен. Кажется законным для меня :)

        // Try to use the native JSON parser first
        return window.JSON && window.JSON.parse ?
            window.JSON.parse( data ) :
            (new Function("return " + data))();

Как неоднократно говорилось, считается, что плохой практикой является использование конструктора Function (также см. Спецификацию языка ECMAScript , 5- е издание, § 15.3.2.1):

new Function ([arg1[, arg2[, … argN]],] functionBody)

(где все аргументы - это строки, содержащие имена аргументов, а последняя (или единственная) строка содержит тело функции).

Чтобы повторить это, говорят, что он медленный, как объясняет команда Opera :

Каждый раз, когда [...] конструктор Function вызывается в строке, представляющей исходный код, механизм сценария должен запустить механизм, который преобразует исходный код в исполняемый код. Это обычно дорого для производительности - например, в сто раз дороже, чем простой вызов функции. (Марк Тарквин «Уилтон-Джонс»)

Хотя это не так уж плохо, согласно этому сообщению на MDC (я не тестировал это сам, используя текущую версию Firefox, хотя).

Крокфорд adds что

[t] он цитирует условные обозначения языка, что очень сложно правильно выразить тело функции как строку. В строковой форме ранняя проверка ошибок не может быть выполнена. [...] И это расточительно для памяти, потому что каждая функция требует собственной независимой реализации.

Другое отличие состоит в том, что

функция, определенная конструктором Function, не наследует ни одну область, кроме глобальной области (которую все функции наследуют). ( MDC )

Помимо этого, вы должны быть внимательны, чтобы избежать инъекции вредоносного кода при создании new Function с использованием динамического содержимого.

Тем не менее, TJ Кроудер говорит в ответ, что

[t] здесь почти никогда не требуется аналогичная [...] новая функция (...), опять же, за исключением некоторых случаев с расширенными краями.

Итак, теперь мне интересно: что это за «передовые случаи края»? Есть ли законное использование конструктора Function?


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

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

Вы можете комбинировать эти два и скомпилировать их в одном месте и выполнить их на другом, и все же удастся передать аргументы в переменных, которые ожидают строки кода.


Единственное законное использование, к которому я пришел, - это когда я написал это:

Function.prototype.New = (function () {
  var fs = [];
  return function () {
    var f = fs [arguments.length];
    if (f) {
      return f.apply (this, arguments);
    }
    var argStrs = [];
    for (var i = 0; i < arguments.length; ++i) {
      argStrs.push ("a[" + i + "]");
    }
    f = new Function ("var a=arguments;return new this(" + argStrs.join () + ");");
    if (arguments.length < 100) {
      fs [arguments.length] = f;
    }
    return f.apply (this, arguments);
  };
}) ();

Код позволяет использовать Function.prototype.apply при использовании new ключевого слова.

Пример:

function Foo (x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
  this.otherArgs = Array.prototype.slice.call (arguments, 3);
}

var foo = Function.prototype.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New (1, 2, 3, 4, 5, 6, 7);
var bool = true
  && foo.x == 1
  && foo.y == 2
  && foo.z == 3
  && foo.otherArgs.length == 4
  && foo.otherArgs [0] == 4
  && foo.otherArgs [1] == 5
  && foo.otherArgs [2] == 6
  && foo.otherArgs [3] == 7
  ;

alert (bool);

Это отдельный случай из моего другого ответа.

Я использовал конструктор Function некоторое время назад для создания настраиваемых форматировщиков строк, которые вызывались повторно. Накладные расходы на создание функции (которая, как я понимаю, проблема с производительностью, о которой вы говорите) были намного перевешимы благодаря улучшенной производительности настраиваемых функций, которые были созданы во время выполнения специально для обработки определенной строки формата, и, следовательно, не нужно было оценивать тонны нерелевантных случаев - или анализировать строку формата, если на то пошло. Похоже, это похоже на компиляцию регулярного выражения.


NWMatcher - Селектор и NWMatcher CSS Javascript, Диего Перини - использует конструктор Function ( 1 , 2 , 3 , 4 и т. Д.) Для создания («компиляции») высокоэффективных версий селекторов выбора.

Тест (который я только что запускал на Chrome 5) говорит сам за себя:

Обратите внимание на разницу между NWMatcher и Sizzle, которая очень похожа на механизм выбора, только без компиляции функций :)

С другой стороны, ECMAScript 5 не вызывает ошибок при вызове Function . Ни в строгом, ни в «стандартном» режимах. Строгий режим, однако, вводит несколько ограничений на присутствие идентификаторов, таких как «eval» и «arguments»:

  • Вы не можете объявлять переменные / функции / аргументы с такими именами:

    function eval() { }
    var eval = { };
    function f(eval) { } 
    var o = { set f(eval){ } };
    
  • Вы не можете назначить такой идентификатор:

    eval = { };
    

Также обратите внимание, что в строгом режиме семантика eval немного отличается от семантики ES3. Строгий режимный код не может создавать переменные или функции в среде, из которой он был вызван:

 eval(' "use strict"; var x = 1; ');
 typeof x; // "undefined"




function-constructor