Косвенный вызов функции в JavaScript

Есть такие вещи, как

f.call(...)
f.apply(...)

Но тогда это

(1, alert)('Zomg what is this????!!!11')

"1" в этом контексте, похоже, мало значит, следующее работает отлично:

(null, alert)('Zomg what is this????!!!11')
(1, null, alert)('Zomg what is this????!!!11')
(undefined, alert)('Zomg what is this????!!!11')

Не могли бы вы указать на определенную часть ECMAScript, которая описывает этот синтаксис?

Ответы

Ответ 1

Вы используете Оператор Comma.

Этот оператор только оценивает свои операнды слева направо и возвращает значение из второго, например:

(0, 1); // 1
('foo', 'bar'); // 'bar'

В контексте вызова функции оценка операнда будет просто получать значение, а не ссылку, это приводит к тому, что значение this внутри вызываемой функции указывает на глобальный объект (или это будет undefined в новом строком режиме ECMAScript 5).

Например:

var foo = 'global.foo';

var obj = {
  foo: 'obj.foo',
  method: function () {
    return this.foo;
  }
};

obj.method();      // "obj.foo"
(1, obj.method)(); // "global.foo"

Как вы можете видеть, первый вызов, который является прямым вызовом, значение this внутри method будет правильно ссылаться на obj (возврат "obj.foo"), второй вызов, оценка, сделанная оператор запятой сделает значение this, чтобы указать на глобальный объект (давая "global.foo").

Этот шаблон стал довольно популярным в наши дни, чтобы сделать косвенные вызовы eval, это может быть полезно в строгом режиме ES5, например, для получения ссылки на глобальный объект (предположим, что вы находитесь в среде без браузера, window недоступен):

(function () {
  "use strict";
  var global = (function () { return this || (1,eval)("this"); })();
})();

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

Оператор || теперь возьмет второй операнд, вызов eval, который является косвенным вызовом, и он будет оценивать код в глобальной лексической и переменной среде.

Но лично, в этом случае, в строгом режиме я предпочитаю использовать конструктор Function для получения глобального объекта:

(function () {
  "use strict";
  var global = Function('return this')();
})();

Функции, созданные с помощью конструктора Function, строгие, только если они начинаются с Использовать Strict Directive, они не "наследуют" строгость текущего контекста, как объявления функций или выражения функций.

Ответ 2

Это оператор запятой, который оценивает оба его операнда и возвращает значение второго.

Итак, что-то вроде (null, alert) оценивает функцию alert, которую вы можете немедленно вызвать с помощью круглых скобок.

Это описано в разделе 11.14 ECMA-262 (PDF).