14

为什么这段代码会抛出错误?

// global non-strict code
(function eval () { 'use strict'; });

现场演示:http: //jsfiddle.net/SE3eX/1/

所以,我们这里有一个命名函数表达式。我想明确指出这个函数表达式出现在非严格代码中。如您所见,它的函数体是严格的代码。

严格模式规则在这里:http ://ecma-international.org/ecma-262/5.1/#sec-C

相关的项目符号是这个(它是列表中的最后一个):

在严格模式代码中使用标识符 eval 或 arguments 作为 FunctionDeclaration 或 FunctionExpression 的标识符或形式参数名称 (13.1) 是 SyntaxError。尝试使用 Function 构造函数 (15.3.2) 动态定义此类严格模式函数将引发 SyntaxError 异常。

请注意,仅当函数声明/表达式本身出现在严格的代码中时,此规则才适用,而在我上面的示例中则没有。

但它仍然会抛出错误?为什么?

4

3 回答 3

10

§13.1概述了在您的情况下应该发生的情况:

  • 如果任何 Identifier 值在严格模式 FunctionDeclaration 或 FunctionExpression 的 FormalParameterList 中出现多次,则为 SyntaxError。
  • 如果标识符“eval”或标识符“arguments”出现在严格模式 FunctionDeclaration 或 FunctionExpression 的 FormalParameterList 中,则为 SyntaxError。
  • 如果标识符“eval”或标识符“arguments”作为严格模式 FunctionDeclaration 或 FunctionExpression 的标识符出现,则为 SyntaxError。

强调我的。您的严格模式函数的标识符eval,因此,它是SyntaxError. 游戏结束。


要了解上述为什么是“严格模式函数表达式”,请查看第 13 节(函数定义)中的语义定义:

产生式
FunctionExpression : function Identifier opt ( FormalParameterList opt ) { FunctionBody } 的评估如下:

  1. 返回创建一个新的函数对象的结果,如 13.2 中指定的,参数由 FormalParameterListopt 指定,主体由 FunctionBody 指定。传入正在运行的执行上下文的 LexicalEnvironment 作为 Scope。如果 FunctionExpression 包含在严格代码中或其 FunctionBody 是严格代码,则传入 true 作为 Strict 标志。

强调我的。上面显示了函数表达式(或声明)如何变得严格。它所说的(用简单的英语)是FunctionExpressionstrict两种情况下:

  1. 它是从use strict上下文中调用的。
  2. 它的函数体以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.

于 2012-09-24T16:58:49.740 回答
3

好问题!

因此,要找到您的问题的答案,您实际上需要查看声明函数的过程(特别是步骤 3-5 - 添加了重点):

  1. ...
  2. ...
  3. 调用envRec的 CreateImmutableBinding 具体方法,传入Identifier的 String 值作为参数。
  4. 闭包是创建一个新的函数对象的结果,如 13.2 中指定的,其参数由FormalParameterList opt指定,主体由FunctionBody指定。传入 funcEnv作为Scope 如果FunctionExpression包含在严格代码中或其FunctionBody是严格代码,则传入true 作为Strict标志
  5. 调用 envRec 的 InitializeImmutableBinding 具体方法,传递 Identifier 的 String 值和闭包作为参数。

因此,当绑定在第 3 步中创建时,您对 eval 的使用不是问题,但是一旦到达第 5 步,它就会尝试eval在严格的词法环境中初始化绑定(即,将某些内容分配给eval),这是不允许的,因为我们在第 4 步之后处于严格的上下文中。

请记住,限制不在于初始化新eval变量。它将它用作赋值运算符的LeftHandSideExpression,这就是函数声明过程的第 5 步中发生的事情。

更新:

正如@DavidTitarenco 指出的那样,这在第13.1节中明确涵盖(除了第13节中的隐式限制)。

于 2012-09-24T16:59:36.063 回答
1

我猜它会引发错误,因为函数 eval 内部会指向现在违反严格模式的函数本身。

于 2012-09-24T16:56:36.813 回答