(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 гарантированно будут выполняться в глобальном масштабе.

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

  1. При каких обстоятельствах прямой вызов eval не выполняется в глобальном масштабе?
  2. При каких обстоятельствах 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

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