Javascript 严格模式下的间接评估调用
我了解Javascript 严格模式下的间接评估调用,javascript,eval,ecmascript-5,Javascript,Eval,Ecmascript 5,我了解eval()如何在非严格上下文中工作,但是在严格模式下使用eval()的情况完全让我困惑。当在全局范围内直接调用eval()时,变量将保留在新的eval()范围内: 'use strict'; eval('var a = 1;'); console.log(a); // ReferenceError: a is not defined 但是,如果我在全局范围内执行对eval()的间接调用(应该是相同的,对吧?),它的行为就好像它不是在严格模式下(如果您不相信我,请参阅): 如果您不了解(
eval()
如何在非严格上下文中工作,但是在严格模式下使用eval()
的情况完全让我困惑。当在全局范围内直接调用eval()
时,变量将保留在新的eval()
范围内:
'use strict';
eval('var a = 1;');
console.log(a); // ReferenceError: a is not defined
但是,如果我在全局范围内执行对eval()
的间接调用(应该是相同的,对吧?),它的行为就好像它不是在严格模式下(如果您不相信我,请参阅):
如果您不了解(0,eval)
的作用,请参阅
至少根据我对eval()
如何在严格模式下工作的理解,它意味着(无论是直接调用还是间接调用eval()
)为eval()
调用中定义的变量创建一个新的作用域,但这里的情况似乎不是这样。规范说明如下:
输入评估代码
当控件进入eval代码的执行上下文时,将执行以下步骤:
B将设置为与调用执行上下文相同的值。
C将设置为与调用执行上下文的值相同的值
B将设置为strictVarEnv。
C将设置为strictVarEnv
eval()
(是的,我知道使用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
})();
这一问题可以从以下方面看出:
如果eval代码是严格的代码,那么(me:fix-context)
但严格的评估代码定义为:
如果Eval代码以包含Use strict指令的指令序言开头,或者对Eval的调用是直接调用,则Eval代码为严格Eval代码
因为调用不是直接的,所以eval代码不是严格的eval代码,执行是在全局范围内的
首先是个好问题
“Eval Code”比直接或间接调用Eval
更通用
让我们检查一下确切的规格
15.1.2.1评估(x)
使用一个参数x调用eval函数时,将执行以下步骤:
如果类型(x)不是字符串,则返回x
让prog成为ECMAScript代码,它是将x解析为程序的结果。如果解析失败,抛出SyntaxError异常(但也请参见第16条)
让evalCtx成为为eval代码程序建立新执行上下文的结果
让结果作为评估程序进度的结果
退出正在运行的执行上下文evalCtx,恢复以前的执行上下文。
那么,让我们来探讨10.4.2告诉我们的内容,您引用了-具体来说,让我们看看第一条:
如果没有调用上下文,或者如果对eval函数的直接调用(15.1.2.1.1)未对eval代码求值,则。。。初始化执行上下文,就像它是全局执行上下文一样
那么什么是直拨电话?
对eval函数的直接调用表示为满足以下两个条件的CallExpression:
作为对CallExpression中的MemberExpression求值的结果的引用有一个环境记录作为其基值,其引用名称为“eval”
以该引用作为参数调用抽象操作GetValue的结果是15.1.2.1中定义的标准内置函数
那么,这两种情况下的成员表达式是什么
在eval('var a=1;')
实际上,对其求值的结果有一个引用名eval
,对其调用GetValue
resolution将返回内置函数
在(0,eval)('var a=1;')代码>计算成员表达式的结果没有引用名称eval
。(但它确实解析为GetValue上的内置函数)
引用名称是什么?
第二节告诉我们:
引用是已解析的名称绑定。引用由三个组件组成:基值、引用名称和布尔值严格引用标志。基值可以是未定义的、对象、布尔值、字符串、数字或环境记录(10.2.1)。未定义的基值表示无法将引用解析为绑定。引用的名称是一个字符串
这需要我们查看getReferenceName
:
GetReferencedName(V)。返回引用V的引用名称组件
因此,虽然表达式(0,eval)===eval
为真,但在计算函数时,由于命名的原因,这实际上是一个间接调用
我可以提供函数
构造函数吗:)?我觉得这是个bug。你是如何执行代码的
(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
})();