(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;
}());
5 ответов
Разница между (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 не выполняется в глобальном масштабе?
- При каких обстоятельствах
this
функции в глобальной области видимости не дают глобального объекта?
Еще немного информации можно почерпнуть здесь.
РЕДАКТИРОВАТЬ
Видимо, ответ на мой первый вопрос "почти всегда". Прямой 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), но только очень намеренно.
Я хочу сказать, что ваш источник страдает от легкой и обратимой кранио-ректальной инверсии и может подумать о том, чтобы потратить неделю на программирование на Хаскелле.
Фрагмент,
var global = (function () {
return this || (1, eval)('this');
}());
будет правильно оценивать глобальный объект даже в строгом режиме. В нестрогом режиме значение this
это глобальный объект, но в строгом режиме это undefined
, Выражение (1, eval)('this')
всегда будет глобальным объектом. Причина этого заключается в правилах вокруг косвенных стихов прямой eval
, Прямые звонки на eval
имеет область действия вызывающей стороны и строки this
оценил бы к значению this
в закрытии. непрямой eval
оценивать в глобальной области, как если бы они выполнялись внутри функции в глобальной области. Поскольку эта функция сама по себе не является функцией строгого режима, глобальный объект передается как this
а затем выражение 'this'
оценивает глобальный объект. Выражение (1, eval)
это просто причудливый способ заставить eval
быть косвенным и вернуть глобальный объект.
A1: (1, eval)('this')
это не то же самое, что eval('this')
из-за специальных правил вокруг косвенного стиха прямые призывы к eval
,
A2: оригинал работает в строгом режиме, модифицированные версии нет.
К 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/
Q1: Несколько последовательных операторов javascript, разделенных запятой, принимают значение последнего оператора. Так:
(1, eval)
принимает значение последнего, которое является ссылкой на функцию eval()
функция. Это, очевидно, делает это таким образом, чтобы сделать eval()
вызов косвенного вызова eval, который будет оцениваться в глобальной области видимости в ES5. Подробности объясняются здесь.
Q2: должна быть какая-то среда, которая не определяет глобальный this
, но определяет eval('this')
, Это единственная причина, по которой я могу думать об этом.
Очень хорошее объяснение этому можно найти здесь: https://2ality.com/2015/12/references.html