Косвенный вызов функции в 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, которая описывает этот синтаксис?

3 ответа

Решение

Вы просто используете оператор запятой.

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

(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 конструкторы строгие, только если они начинаются с директивы Use Strict, они не "наследуют" строгость текущего контекста, как это делают объявления функций или выражения функций.

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

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

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

Оператор запятой заставляет выражения вычисляться последовательно. Заключение выражений в скобки возвращает значение последнего выражения. Так (1, alert)("hello") функционально эквивалентно:

1;
alert("hello");

Сверху головы я не могу придумать причину сделать это.

Другие вопросы по тегам