(如果函数体处于严格模式,函数eval(){})会抛出语法错误?

时间:2012-09-24 16:32:35

标签: javascript theory

为什么此代码会抛出错误?

// 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异常。

请注意,如果函数声明/表达式本身出现在严格的代码中,并且在上面的示例中,则此规则仅适用。

但它仍然会出错?为什么呢?

3 个答案:

答案 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 }    评估如下:

     
      
  1. 返回使用FormalParameterListopt和body指定的参数创建13.2中指定的新Function对象的结果   由FunctionBody指定。通过词汇环境   将执行上下文作为Scope运行。 严格传递真实   如果FunctionExpression包含在严格的代码中,或者如果它包含,则标记   FunctionBody是严格的代码。
  2.   

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

  1. use strict上下文调用它。
  2. 其功能正文以use strict开头。
  3. 您的困惑源于认为只有函数体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 - 强调添加):

  
      
  1. ...
  2.   
  3. ...
  4.   
  5. 调用 envRec 的CreateImmutableBinding具体方法,将 Identifier 的String值作为参数传递。
  6.   
  7. 闭包是创建一个新的Function对象的结果,该对象在13.2中指定,参数由 FormalParameterList opt 指定,并且由< EM>函数体。将 funcEnv 作为范围传递。 如果功能表达式,则传入true作为严格标志 包含在严格的代码中或如果 FunctionBody是严格的代码。
  8.   
  9. 调用envRec的InitializeImmutableBinding具体方法,将Identifier和closure的String值作为参数传递。
  10.   

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

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

<强>更新

正如@DavidTitarenco指出的那样,13.1部分明确涵盖了这一点(除13部分中的隐含限制外)。

答案 2 :(得分:1)

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