为什么严格模式不限制标识符"eval" 和 "arguments"显示为标签名称?



所以,你可能知道,JavaScript的严格模式增加了对标识符的限制evalarguments,有效地使它们成为保留字,但有两个例外:

  • 它们仍然可以用作表达式,即在需要表达式的地方(不过有几个例外),
  • 它们仍然可以用作标签名称,并在break/continue语句中引用标签。

现在,我明白了第一颗子弹。例如,如果不允许将标识符eval作为表达式(而真正的保留字则不允许),我们将根本无法调用eval函数(因为eval(str)是一个表达式)。arguments也是如此 - 我们需要能够将其用作表达式才能访问其元素(例如arguments[0])。

不过,此规则有三个例外。eval/arguments可能不会在作业中显示为左侧表达式(例如eval = true;), (2) 作为++/--的操作数(例如eval++), (3) 作为delete的操作数(例如delete eval)。不过,这些是唯一的例外,在所有其他表达式上下文中,它们都是有效的。

我不明白的是第二颗子弹。为什么它们仍然可以用作标签名称?例如,即使在严格模式下,此代码也有效:

eval: for ( var i = 0; i < 10; i++ ) {
arguments: for ( var j = 0; j < 10; j++ ) {
if ( i < j ) continue eval;
console.log( i - j );    
}        
}

请注意continue eval;如何引用eval标签,与实际的eval函数无关。

另请注意,真正的保留字不能用作标签名称。根据我的理解,严格模式的意图是使名称eval,并且arguments尽可能像保留词一样。那为什么要将它们保留为有效的标签名称呢?

我不知道为什么,但我可以冒险猜测一个很好的猜测。

evalarguments仅限于变量名的原因是(就此而言,为什么禁止with)是因为它们会影响变量名的绑定位置(即到局部变量、封闭范围内的变量或全局对象上的属性(如果存在)。 如果没有这些限制,某些名称在运行时之前是不受约束的,这意味着所有危险。

标签名称占用与变量名称、属性名称等不同的命名空间。break/continue的目标永远不会有歧义,因为标签是静态分配的,标签引用是静态解析的。 (是的,eval代码可以包含标签。 但是现有的跳转不能以这些标签为目标,eval代码中的跳转也不能以预先存在的标签为目标,因为标签解析发生在编译时,并且它的范围限定为程序,以使用 ECMAScript 终端的名称。 包含eval调用的脚本是程序,eval调用执行的代码是程序,但出于标签定位目的,两者是完全分开的。

禁止变量名称evalarguments的原因根本不适用于标签。 因此,标签仍可命名为evalarguments。 以这种方式命名标签是愚蠢的,真的。 如果有人再次设计 ECMAScript/JavaScript,它们将是关键字,不能用作标签名称。 但是禁止它们作为标签名称没有任何好处,而且至少有一个不禁止它们的兼容性论据,所以它们没有被禁止。

最新更新