Javascript (函数eval(){})在函数体处于严格模式时抛出语法错误?

Javascript (函数eval(){})在函数体处于严格模式时抛出语法错误?,javascript,theory,Javascript,Theory,为什么这段代码会抛出错误 // global non-strict code (function eval () { 'use strict'; }); 现场演示: 我们这里有一个命名函数表达式。我想明确指出,这个函数表达式出现在非严格代码中。如您所见,它的函数体是严格的代码 严格的模式规则如下: 相关的项目符号是这个(它是列表上的最后一个): 在严格模式代码中使用标识符eval或参数作为函数声明或函数表达式的标识符或形式参数名(13.1)是一种语法错误。尝试使用函数构造函数(15.3.2)动

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

// global non-strict code
(function eval () { 'use strict'; });
现场演示:

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

严格的模式规则如下:

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

在严格模式代码中使用标识符eval或参数作为函数声明或函数表达式的标识符或形式参数名(13.1)是一种语法错误。尝试使用函数构造函数(15.3.2)动态定义此类严格模式函数将引发SyntaxError异常

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


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

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

概述了在类似您的情况下应该发生什么:

  • 如果任何标识符值在严格模式函数声明或声明的FormalParameterList中出现多次,则为SyntaxError 函数表达式
  • 如果标识符“eval”或标识符“arguments”出现在严格模式的-FormalParameterList中,则为语法错误 FunctionDeclaration或FunctionExpression
  • 如果标识符“eval”或标识符“arguments”作为严格模式的标识符出现,则为语法错误 函数声明或函数表达式。
我的。严格模式函数的标识符是
eval
,因此,它是一个
SyntaxError
。比赛结束了


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

生产过程
函数表达式:
function
Identifieropt
FormalParameterListopt
){
FunctionBody
}
评估结果如下:

  • 返回使用FormalParameterListopt和body指定的参数创建13.2中指定的新函数对象的结果 由FunctionBody指定。将词汇环境传递给 将执行上下文作为作用域运行将true作为严格的 如果FunctionExpression包含在严格代码中或其 函数体是严格的代码。
  • 我的。上面显示了函数表达式(或声明)是如何变得严格的。它的意思是(用简单的英语)函数表达式在两种情况下是严格的:

  • 它是从
    使用严格的
    上下文调用的
  • 其函数体以
    使用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

    好问题

    因此,要找到问题的答案,您实际上需要查看以下步骤(具体来说,步骤3-5——增加了重点):

  • 调用envRec的CreateImmutableBinding具体方法,传递标识符的字符串值作为参数
  • 让闭包作为创建一个新函数对象的结果,如13.2所述,该对象的参数由FormalParameterListopt指定,主体由FunctionBody指定。传入funcEnv作为作用域如果FunctionExpression包含在严格代码中,则传递true作为严格标志;如果FunctionBody是严格代码,则传递true作为严格标志。
  • 调用envRec的initializeimutablebinding具体方法,将标识符和闭包的字符串值作为参数传递。
  • 因此,在步骤3中创建绑定时,eval的使用不是问题,但一旦进入步骤5,它将尝试在严格的词汇环境中初始化
    eval
    的绑定(即,将某些内容分配给
    eval
    ),这是不允许的,因为在第4步之后,我们处于一个严格的环境中

    请记住,该限制不适用于初始化新的
    eval
    变量。将其用作赋值运算符的LeftHandSideExpression,这是函数声明过程的第5步

    更新:


    正如@DavidItarenco所指出的,这在第节中有明确的说明(除了第节中的隐式限制)。

    这里完全是猜测,但这可能与以下事实有关:在表达式中,具有名称的函数实例化表达式仅在函数内绑定该名称;换句话说,在内部,似乎有一种神奇的方法可以让
    var
    声明创建一个局部变量,该局部变量通过引用函数初始化。因此,就好像您试图在本地绑定全局符号“eval”。@这是一个很好的提示。我必须检查标准,以确定在该场景中到底发生了什么…您只使用
    Function eval(){'use strict';}得到相同的错误消息(SyntaxError:Function name可能不是eval或strict模式下的参数)并且这不会产生语法错误:
    window.eval=function(){'use strict';}锁定它。这正是这里发生的事情,所以在非严格代码中出现的函数表达式,但其函数体是严格代码,是一个“严格模式”