(1, eval) ('this') против eval ('this') в JavaScript?

Я начинаю читать шаблон JavaScript, некоторые коды путают меня.

var global = (function () {
    return this || (1, eval)('this');
}());

Вот мои вопросы:

Q1:

(1, eval) === eval?

Почему это работает? Как?

Q2: Почему не просто

var global = (function () {
    return this || eval('this');
}());

или

 var global = (function () {
    return this;
}());

Может ли кто-нибудь сказать мне? Спасибо.

Ответ 1

Разница между (1,eval) и обычным старым eval заключается в том, что первое значение, а последнее - lvalue. Было бы более очевидным, если бы это был другой идентификатор:

var x;
x = 1;
(1, x) = 1; //  syntax error, of course!

Это (1,eval) - выражение, которое дает eval (как говорят, (true && eval) или (0 ? 0 : eval)), но это не ссылка на eval.

Почему вас это волнует?

Ну, спецификация Ecma рассматривает ссылку на eval как "прямой вызов eval", но выражение, которое просто дает eval как косвенный, - и косвенные вызовы eval гарантируют выполнение в глобальном сфера.

Вещи, которые я до сих пор не знаю:

  • При каких обстоятельствах прямой вызов eval не выполняется в глобальной области?
  • При каких обстоятельствах функция this функции в глобальной области не может дать глобальный объект?

Более подробную информацию можно получить здесь.

EDIT

По-видимому, ответ на мой первый вопрос "почти всегда". Прямой eval выполняется из текущей области. Рассмотрим следующий код:

var x = 'outer';
(function() {
  var x = 'inner';
  eval('console.log("direct call: " + x)'); 
  (1,eval)('console.log("indirect call: " + x)'); 
})();

Не удивительно (хе-хе), это печатает:

direct call: inner
indirect call: outer

ИЗМЕНИТЬ

После большего количества экспериментов я в предварительном порядке скажу, что this не может быть установлен в null или undefined. Он может быть установлен на другие значения фальши (0, '', NaN, false), но только очень преднамеренно.

Я хочу сказать, что ваш источник страдает от мягкой и обратимой черепно-ректальной инверсии и может захотеть рассмотреть возможность недельного программирования в Haskell.

Ответ 2

Фрагмент

var global = (function () {  
    return this || (1, eval)('this');  
}());  

будет правильно оценивать глобальный объект даже в строгом режиме. В нестрогом режиме значение this является глобальным объектом, но в строгом режиме оно undefined. Выражение (1, eval)('this') всегда будет глобальным объектом. Причиной этого являются правила вокруг непрямых стихов direct eval. Прямые вызовы eval имеют область вызова вызывающего, а строка this будет оценивать значение this в закрытии. Косвенные eval оцениваются в глобальной области видимости, как если бы они выполнялись внутри функции в глобальной области. Поскольку эта функция сама по себе не является функцией строгого режима, глобальный объект передается как this, а затем выражение 'this' оценивается глобальным объектом. Выражение (1, eval) является просто причудливым способом принудительного eval быть косвенным и возвращать глобальный объект.

A1: (1, eval)('this') не совпадает с eval('this') из-за специальных правил вокруг прямых прямых звонков на eval.

A2: оригинал работает в строгом режиме, модифицированные версии этого не делают.

Ответ 3

В Q1:

Я думаю, что это хороший пример оператора запятой в JS. Мне нравится объяснение для оператора запятой в этой статье: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/

Оператор запятой оценивает оба своих операнда (слева направо) и возвращает значение второго операнда.

В Q2:

(1, eval)('this') рассматривается как косвенный вызов eval, который в ES5 выполняет код во всем мире. Таким образом, результатом будет глобальный контекст.

См. http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope

Ответ 4

Q1: Несколько последовательных операторов javascript, разделенных запятой, принимают значение последнего оператора. Итак:

(1, eval) принимает значение последнего, которое является ссылкой функции на функцию eval(). По-видимому, это делает так, чтобы вызов eval() включался в косвенный eval-вызов, который будет оцениваться в глобальной области действия ES5. Подробности объяснены здесь.

Q2: Должна быть среда, которая не определяет глобальную this, но определяет eval('this'). Это единственная причина, по которой я могу думать об этом.