(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')
. Это единственная причина, по которой я могу думать об этом.