为什么此代码会抛出错误?
// global non-strict code
(function eval () { 'use strict'; });
现场演示: http://jsfiddle.net/SE3eX/1/
所以,我们这里有一个命名函数表达式。我想明确指出这个函数表达式出现在非严格的代码中。如您所见,它的函数体是严格的代码。
严格模式规则在此处:http://ecma-international.org/ecma-262/5.1/#sec-C
相关的子弹是这个(它是列表中的最后一个):
在严格模式代码中使用的是SyntaxError,标识符eval或arguments作为FunctionDeclaration或FunctionExpression的标识符或作为形式参数名称(13.1)。尝试使用Function构造函数(15.3.2)动态定义此类严格模式函数将引发SyntaxError异常。
请注意,如果函数声明/表达式本身出现在严格的代码中,并且在上面的示例中不,则此规则仅适用。
但它仍然会出错?为什么呢?
答案 0 :(得分:10)
§13.1概述了像你这样的案件应该发生的事情:
- 如果任何标识符值在严格模式FunctionDeclaration的FormalParameterList中出现多次,则为SyntaxError或 FunctionExpression。
- 如果标识符“eval”或标识符“arguments”出现在严格模式的FormalParameterList中,则为SyntaxError FunctionDeclaration或FunctionExpression。
- 如果标识符“eval”或标识符“arguments”作为严格模式的标识符出现,则为SyntaxError FunctionDeclaration或FunctionExpression。
强调我的。您的严格模式函数的标识符是eval
,因此它是SyntaxError
。游戏结束。
要了解上述为什么是“严格模式函数表达式”,请查看§13(函数定义)中的语义定义:
制作
FunctionExpression :function
标识符 opt(
FormalParameterList opt) {
FunctionBody}
评估如下:
- 返回使用FormalParameterListopt和body指定的参数创建13.2中指定的新Function对象的结果 由FunctionBody指定。通过词汇环境 将执行上下文作为Scope运行。 严格传递真实 如果FunctionExpression包含在严格的代码中,或者如果它包含,则标记 FunctionBody是严格的代码。
醇>
强调我的。上面显示了函数表达式(或声明)如何变得严格。它(用简单的英语)说的是 FunctionExpression 在两种情况下是strict
:
use strict
上下文调用它。use strict
开头。您的困惑源于认为只有函数体是strict
,而事实上,整个函数表达式是strict
。您的逻辑虽然直观,但并不是JS的工作原理。
如果您想知道为什么ECMAscript以这种方式工作,那就非常简单了。假设我们有这个:
// look ma, I'm not strict
(function eval() {
"use strict";
// evil stuff
eval(); // this is a perfectly legal recursive call, and oh look...
// ... I implicitly redefined eval() in a strict block
// evil stuff
})();
值得庆幸的是,上面的代码将抛出,因为整个函数表达式被标记为strict
。
答案 1 :(得分:3)
很棒的问题!
因此,要找到问题的答案,您实际上需要查看process for declaring a function(具体而言,步骤3-5 - 强调添加):
- ... 的
- ... 的
- 调用 envRec 的CreateImmutableBinding具体方法,将 Identifier 的String值作为参数传递。
- 让闭包是创建一个新的Function对象的结果,该对象在13.2中指定,参数由 FormalParameterList opt 指定,并且由< EM>函数体。将 funcEnv 作为范围传递。 如果功能表达式>,则传入true作为严格标志 包含在严格的代码中或如果 FunctionBody是严格的代码。
- 调用envRec的InitializeImmutableBinding具体方法,将Identifier和closure的String值作为参数传递。
醇>
因此,当在第3步中创建绑定时,使用eval不是问题,但是一旦它到达第5步,它就会尝试在严格的词法中初始化eval
的绑定环境(即将内容分配给eval
),这是不允许的,因为我们在第4步之后处于严格的上下文中。
请记住,限制不是初始化新的eval
变量。它正在使用它作为赋值运算符的 LeftHandSideExpression ,这是在函数声明过程的第5步中发生的。
<强>更新强>
答案 2 :(得分:1)
我猜测它会抛出一个错误,因为在函数eval中会指向现在违反严格模式的函数本身。