Я начинаю читать шаблоны 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;
}());
javascript
eval
Shawjia
источник
источник
Ответы:
Разница между
(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)'); })();
Неудивительно (хе-хе), это распечатывает:
РЕДАКТИРОВАТЬ
После дополнительных экспериментов я временно скажу, что
this
нельзя установить наnull
илиundefined
. Он может быть установлен на другие ложные значения (0, '', NaN, false), но только очень намеренно.Я собираюсь сказать, что ваш источник страдает легкой и обратимой кранио-ректальной инверсией и может подумать о том, чтобы потратить неделю на программирование на Haskell.
источник
value
противlvalue
(ну, может быть, на практике, но не на словах). Ни правила ES5 eval (не то, чтобы мне разумно былоeval
когда-либо использовать ). Благодарность!eval
него много неприятных острых краев, и его следует использовать только в крайнем случае и очень, очень осторожно.innerHtml
eval
частью MemberExpression CallExpression и ссылаться на стандартнуюeval
функцию.eval
в качестве цели выражения вызова, является особенным. Вы утверждаете , что ECMA рассматривает ссылки наeval
особенный , которые он не делает. Это размещение в выражении вызова является особенным, поскольку выражение оценивает стандартнуюeval
функцию. Например,var eval = window.eval; eval('1');
по-прежнему является прямым eval и имwindow.eval('1')
не является, хотя в этом случае eval также является lvalue.Фрагмент,
var global = (function () { return this || (1, eval)('this'); }());
будет правильно оценивать глобальный объект даже в строгом режиме. В нестрогом режиме значением
this
является глобальный объект, но в строгом - это такundefined
. Выражение(1, eval)('this')
всегда будет глобальным объектом. Причина этого заключается в правилах, касающихся косвенных стихов, прямыхeval
. Прямые вызовыeval
имеют область действия вызывающего, и строкаthis
будет оцениваться как значениеthis
в закрытии. Косвенныеeval
s оцениваются в глобальной области, как если бы они были выполнены внутри функции в глобальной области. Поскольку эта функция сама по себе не является функцией строгого режима, глобальный объект передается как,this
а затем выражение'this'
оценивается в глобальный объект. Выражение(1, eval)
- всего лишь причудливый способ заставитьeval
быть косвенным и возвращать глобальный объект.A1:
(1, eval)('this')
это не то же самое,eval('this')
что из-за особых правил, касающихся прямых обращений к косвенным стихамeval
.О2: Оригинал работает в строгом режиме, модифицированные версии - нет.
источник
К Q1:
Думаю, это хороший пример оператора запятой в JS. Мне нравится объяснение оператора запятой в этой статье: http://javascriptweblog.wordpress.com/2011/04/04/the-javascript-comma-operator/
Оператор запятая оценивает оба своих операнда (слева направо) и возвращает значение второго операнда.
К 2 кварталу:
(1, eval)('this')
считается косвенным вызовом eval, который в ES5 выполняет код глобально. Таким образом, результатом будет глобальный контекст.См. Http://perfectionkills.com/global-eval-what-are-the-options/#evaling_in_global_scope
источник
Q1: несколько последовательных операторов javascript, разделенных запятой, принимают значение последнего оператора. Так:
(1, eval)
принимает значение последнего, которое является ссылкой наeval()
функцию. Очевидно, он делает это таким образом, чтобы сделатьeval()
вызов косвенным вызовом eval, который будет оцениваться в глобальной области видимости в ES5. Подробности объяснены здесь .Q2: Должна быть некоторая среда, которая не определяет глобальную
this
, но определяетeval('this')
. Это единственная причина, по которой я могу это придумать.источник
/eval\(/g
?eval
код d выполняется в собственном контексте, а не в глобальном контексте или окружающем контексте. Один из способов обойти это - косвенно ссылаться на него, как на рассматриваемый код.