2012-09-24 28 views
14

这段代码为什么会引发错误?(function eval(){})如果函数体在严格模式下会引发语法错误?

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

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

所以,我们在这里的是一个名为函数表达式。我想明确指出这个函数表达式出现在非严格的代码中。正如你所看到的,它的功能体是严格的代码。

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

相关的子弹是这个(它是名单上的最后一个):

It is a SyntaxError to use within strict mode code the identifiers eval or arguments as the Identifier of a FunctionDeclaration or FunctionExpression or as a formal parameter name (13.1). Attempting to dynamically define such a strict mode function using the Function constructor (15.3.2) will throw a SyntaxError exception.

注意如何这条规则只适用于当函数声明/表达式本身出现在严格的代码中,它在我上面的示例中不是而是

但它仍然会引发错误?为什么?

+3

这里只是完全猜测,但也许它与这样的事实有关:在*表达式*中,具有名称的函数实例化表达式仅在该函数内将该名称绑定*;换句话说,它在内部就好像有一种'var'声明创建一个局部变量的魔术方式,该局部变量是通过引用该函数来初始化的。因此,就好像你试图在本地绑定全局符号“eval”。 – Pointy

+0

@Pointy好提示。我将不得不检查标准以确定在该场景中到底发生了什么...... –

+1

只有函数eval()会得到相同的错误消息(SyntaxError:函数名称不能是eval或严格模式下的参数) {'严格使用'; };' – some

回答

10

§13.1概括应该是什么的情况下,如你发生:

  • It is a SyntaxError if any Identifier value occurs more than once within a FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression.
  • It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs within a - FormalParameterList of a strict mode FunctionDeclaration or FunctionExpression.
  • It is a SyntaxError if the Identifier "eval" or the Identifier "arguments" occurs as the Identifier of a strict mode FunctionDeclaration or FunctionExpression.

重点煤矿。您的严格模式功能的标识符eval,因此它是SyntaxError。游戏结束。


明白为什么上面是一个“严格模式的功能表现,”看语义定义在§13(函数定义):

The production
FunctionExpression : functionIdentifieropt(FormalParameterListopt) {FunctionBody} is evaluated as follows:

  1. Return the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in the LexicalEnvironment of the running execution context as the Scope. Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.

重点煤矿。以上显示了函数表达式(或声明)如何变得严格。它说什么(用简单的英语)是一个FunctionExpression有两种strict情况:

  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

+1

钉了它。这正是这里发生的事情 – Claudiu

+0

因此,一个函数表达式出现在非严格代码中,但其函数体是严格代码,是一种“严格模式函数表达式”?你能在标准中找到这个定义吗? –

+1

@ŠimeVidashttp://ecma-international.org/ecma-262/5.1/#sec-10.1.1 - “属于FunctionDeclaration,FunctionExpression或访问器PropertyAssignment **的函数代码是严格的函数代码** if其FunctionDeclaration,** FunctionExpression **或PropertyAssignment包含在严格模式代码或**中,如果功能代码以包含使用严格指令**的指令序言开头。 – Pete

1

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

3

伟大的问题!

因此,要找到答案你的问题,你真的需要看看process for declaring a function(具体而言,步骤3-5 - 强调):

  1. ...
  2. ...
  3. Call the CreateImmutableBinding concrete method of envRec passing the String value of Identifier as the argument.
  4. Let closure be the result of creating a new Function object as specified in 13.2 with parameters specified by FormalParameterListopt and body specified by FunctionBody. Pass in funcEnv as the Scope.Pass in true as the Strict flag if the FunctionExpression is contained in strict code or if its FunctionBody is strict code.
  5. Call the InitializeImmutableBinding concrete method of envRec passing the String value of Identifier and closure as the arguments.

那么,什么情况是,你的EVAL使用在步骤3中创建绑定时不是问题,但是一旦它遇到步骤5,它就试图在严格的词汇环境(即分配给eval)中初始化eval的绑定,这是不允许的,因为我们是在严格的情况下,遵循第4步。

请记住,限制不是初始化一个新的eval变量。它使用Assignment操作符的LeftHandSideExpression,这是函数声明过程的第5步中发生的情况。

UPDATE:

正如@DavidTitarenco指出的,这是明确部13.1覆盖(除了隐含限制在部分13)。

+0

嗯,我不认为'InitializeImmutableBinding'使用赋值运算符。源代码中赋值运算符“存在”,而“InitializeImmutableBinding”是内部方法。我怀疑它是在* JavaScript中定义的。 –

+0

@ŠimeVidas你是对的。它似乎没有违反规范的字母,但它似乎违反了规范的*精神*。这是你必须在ECMAScript的常规基础上考虑的问题。 : - /(这是代码,“你的猜测和我一样好” - 我希望我能两次提出这个问题)。 – Pete

相关问题