(1, eval)('this') vs eval('this') 在 JavaScript 中?

IT技术 javascript eval
2021-01-23 13:49:40

我开始阅读JavaScript Patterns,一些代码让我感到困惑。

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

以下是我的问题:

问题 1:

(1, eval) === eval?

为什么以及如何运作?

Q2:为什么不只是

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

或者

 var global = (function () {
    return this;
}());
4个回答

(1,eval)和plain old之间的区别在于eval前者是一个,后者是一个左值。如果是其他标识符会更明显:

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

这是(1,eval)一个产生的表达式eval(就像 say(true && eval)(0 ? 0 : eval)will 一样),但它不是对eval.

你为什么在乎?

好了,规范了Ecma认为一个参考,以eval成为一个“直接的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不能设置为nullundefined它可以设置为其他虚假值(0、''、NaN、false),但只是非常有意地。

我要说的是您的消息来源患有轻度且可逆的颅直肠内翻,可能需要考虑在 Haskell 上花一周时间进行编程。

@Malvolio您似乎在暗示左值与直接与间接评估有关,而他们没有。使用称为eval调用表达式目标的标识符是特殊的。您声明 ECMA 处理special 的引用eval而它不处理。特殊的是调用表达式中的位置,表达式计算为标准eval函数。例如,var eval = window.eval; eval('1');仍然是一个直接的 eval 并且window.eval('1')不是,即使 eval 在这种情况下也是一个左值。
2021-03-13 13:49:40
左值与确定直接 eval 几乎没有关系,因为它通常指的是可以出现在赋值左侧的表达式,因此名称左值而不是右值。对 eval 的调用仅在规范的 15.1.2.1.1 中列出的条件下是直接的,该规范表示标识符必须是eval并且是 CallExpression 的 MemberExpression 部分并引用标准eval函数。
2021-03-21 13:49:40
是的,eval有很多令人讨厌的锋利边缘,只能作为最后的手段,然后非常非常小心地使用。
2021-04-01 13:49:40
我只遇到过一次有效的使用 - 评估已通过以下方式添加到 DOM 的脚本标记 innerHtml
2021-04-06 13:49:40
哇,不知道整个valuevslvalue事情(好吧,实际上可能,但不是文字)。也不是 ES5 eval 规则(不是我应该合理地需要使用eval)。谢谢!
2021-04-08 13:49:40

片段

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

即使在严格模式下也会正确评估全局对象。在非严格模式下, 的值this是全局对象,但在严格模式下是undefined表达式(1, eval)('this')将始终是全局对象。

这样做的原因涉及有关间接与直接的规则eval直接调用eval具有调用者的范围,并且字符串this将评估为this闭包中的值Indirect evals 在全局范围内进行评估,就好像它们在全局范围内的函数内执行一样。

由于该函数本身不是严格模式函数,因此全局对象被传入 asthis然后表达式'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://perfectkills.com/global-eval-what-are-the-options/#evaling_in_global_scope

Q1:用逗号分隔的多个连续 javascript 语句取最后一条语句的值。所以:

(1, eval)取最后一个的值,该值是对函数的函数引用eval()显然这样做是为了将eval()调用变成间接 eval 调用,该调用将在 ES5 的全局范围内进行评估。详情在这里解释

Q2:一定有一些环境没有定义 global this,但确实定义了eval('this'). 这是我能想到的唯一原因。

它与 ES5 严格模式有关。AFAIK 在 ES5 严格模式下,任何eval代码都在其自己的上下文中执行,而不是在全局上下文或封闭上下文中执行。解决此问题的一种方法是像相关代码那样间接引用它。
2021-03-18 13:49:40
也许有人试图躲避不允许的签到钩/eval\(/g
2021-03-19 13:49:40
2021-03-19 13:49:40
@Stoive - 是的,我也想知道类似的事情。如果不是签入钩子,则在过程中的某个地方进行一些过滤(可能是最小化)。
2021-04-04 13:49:40
更新了我的答案以包含来自 CDSanchez 和 @Saxoier 的信息。谢谢。
2021-04-06 13:49:40