gpt4 book ai didi

javascript - 严格模式下的间接 eval 调用

转载 作者:IT王子 更新时间:2023-10-29 02:59:50 26 4
gpt4 key购买 nike

我了解 eval() 在非严格上下文中的工作方式,但是在严格模式下使用 eval() 的情况让我完全困惑。当在全局范围内直接调用 eval() 时,变量将保留在新的 eval() 范围内:

'use strict';
eval('var a = 1;');
console.log(a); // ReferenceError: a is not defined

但是,如果我在全局范围内执行对 eval()间接调用(应该是同一件事,对吧?),它的行为就像是不是严格模式(如果你不相信我,请参阅 this JSFiddle ):

'use strict';
(0, eval)('var a = 1;'); // indirect call to eval
console.log(a); // 1???

有关(0, eval) 作用的解释:参见Why does google main page use (0, obj.func)(args) syntax? .

至少根据我对 eval() 应该如何在严格模式下工作的理解,它的意思是(无论是否直接调用 eval()或间接)为 eval() 调用中定义的变量创建一个新范围,但是这里似乎不是这种情况。 (ECMA-262 规范第 5 版 10.4.2)

所有主流浏览器(包括 Internet Explorer 10、Chrome 30 和 Firefox 24)都是这种情况,因此我认为这不是错误。他们不是都打算做同样的事情吗?如果不是,为什么会这样?

注意:是的,我知道使用 eval() 的“危险”——我只是想了解这背后的逻辑:)

最佳答案

tl;博士

第二个 (0, eval)('var a = 1;'); 实际上不是直接调用。

您可以在以下方面更普遍地看到这一点:

(function(){ "use strict"
var x = eval;
x("var y = 10"); // look at me all indirect
window.y;// 10
eval("var y = 11");
window.y;// still 10, direct call in strict mode gets a new context
})();

问题可见于:

If the eval code is strict code, then (me: fix context)

但严格的 eval 代码定义为:

Eval code is strict eval code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct call.

由于调用不是直接的,因此 eval 代码不是严格的 eval 代码 - 并且在全局范围内执行。


首先是个好问题。

“Eval Code”比直接或间接调用 eval 更通用。

让我们检查一下确切的规范for the eval function

15.1.2.1 eval (x)

When the eval function is called with one argument x, the following steps are taken:

  1. If Type(x) is not String, return x.

  2. Let prog be the ECMAScript code that is the result of parsing x as a Program. If the parse fails, throw a SyntaxError exception (but see also clause 16).

  3. Let evalCtx be the result of establishing a new execution context (10.4.2) for the eval code prog.

  4. Let result be the result of evaluating the program prog.

  5. Exit the running execution context evalCtx, restoring the previous execution context. ...

那么,让我们探讨一下 10.4.2 告诉我们的内容,您引用了它 - 具体来说,让我们看一下第一个子句:

If there is no calling context or if the eval code is not being evaluated by a direct call (15.1.2.1.1) to the eval function then ... Initialise the execution context as if it was a global execution context

那么什么是直接调用呢?

A direct call to the eval function is one that is expressed as a CallExpression that meets the following two conditions:

The Reference that is the result of evaluating the MemberExpression in the CallExpression has an environment record as its base value and its reference name is "eval".

The result of calling the abstract operation GetValue with that Reference as the argument is the standard built-in function defined in 15.1.2.1.

那么,这两种情况下的 MemberExpression 是什么?

eval('var a = 1;'); 中确实评估它的结果有一个引用名称 eval 并调用 GetValue对它的解析返回内置函数。

(0, eval)('var a = 1;'); 中,评估成员表达式的结果没有有一个引用名称 eval 。 (尽管它确实解析为 GetValue 上的内置函数)。

到底什么是引用名?

8.7 in the spec告诉我们:

A Reference is a resolved name binding. A Reference consists of three components, the base value, the referenced name and the Boolean valued strict reference flag. The base value is either undefined, an Object, a Boolean, a String, a Number, or an environment record (10.2.1). A base value of undefined indicates that the reference could not be resolved to a binding. The referenced name is a String.

这需要我们查看 GetReferencedName:

GetReferencedName(V). Returns the referenced name component of the reference V.

因此,虽然表达式 (0,eval) === eval 为真,但在计算函数时,这实际上是一个间接调用,因为命名。

我可以提供 Function 构造函数吗:)?

关于javascript - 严格模式下的间接 eval 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19357978/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com