【问题标题】:(function eval () {}) throws a syntax error if function body is in strict mode?(function eval () {}) 如果函数体处于严格模式,会引发语法错误?
【发布时间】:2012-09-16 03:48:22
【问题描述】:

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

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

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

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

【问题讨论】:

  • 这里只是完全猜测,但也许这与在 表达式 中,具有名称的函数实例化表达式仅绑定该名称的事实有关 within 函数;换句话说,在内部,var 声明似乎有某种神奇的方式来创建一个使用对该函数的引用进行初始化的局部变量。因此,就好像您试图在本地绑定全局符号“eval”。
  • @Pointy 好提示。我必须检查标准以确定在那种情况下到底发生了什么......
  • 只有function eval () { 'use strict'; }; 你会得到同样的错误信息(SyntaxError: Function name may not be eval or arguments in strict mode)
  • 而且这没有语法错误:window.eval = function () { 'use strict'; };

标签: javascript theory


【解决方案1】:

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

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

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


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

产生式
FunctionExpression : function 标识符opt( FormalParameterList选择) { FunctionBody } 评估如下:

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

强调我的。上面显示了函数表达式(或声明)如何变得严格。它所说的(用简单的英语)是 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

【讨论】:

  • 成功了。这正是这里发生的事情
  • 那么出现在非严格代码中,但函数体是严格代码的函数表达式,是不是“严格模式函数表达式”?请问您能在标准中找到这个定义吗?
  • @ŠimeVidas ecma-international.org/ecma-262/5.1/#sec-10.1.1 - “作为 FunctionDeclaration、FunctionExpression 或访问器 PropertyAssignment 一部分的函数代码是严格的函数代码,如果它的 FunctionDeclaration、FunctionExpression b>,或 PropertyAssignment 包含在严格模式代码中,或者如果函数代码以包含 Use Strict 指令的 Directive Prologue 开头。"
  • @ŠimeVidas - 修改了我的答案。
  • @Pete Hm,该定义定义了术语“严格功能代码”,它与“严格模式功能”不同。前者指的是函数内的代码,后者指的是函数本身。
【解决方案2】:

好问题!

因此,要找到您的问题的答案,您实际上需要查看process for declaring a function(具体来说,步骤 3-5 -- 已添加重点):

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

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

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

更新:

正如@DavidTitarenco 所指出的,这在13.1 部分中明确涵盖(除了13 部分中的隐式限制)。

【讨论】:

  • 嗯,我不认为InitializeImmutableBinding 使用赋值运算符。赋值运算符“存在”在源代码中,而InitializeImmutableBinding 是一个内部方法。我怀疑它是在 in JavaScript 中定义的。
  • @ŠimeVidas 你是对的。它似乎没有违反规范的文字,但似乎确实违反了规范的精神。对于 ECMAScript,您必须经常考虑到这一点。 :-/ (那是“你的猜测和我的猜测一样好”的代码——我希望我能两次投票赞成这个问题)。
【解决方案3】:

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

【讨论】:

    猜你喜欢
    • 2012-01-17
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-08
    • 1970-01-01
    相关资源
    最近更新 更多