为什么严格模式不限制标识符“eval"和“arguments"?从作为标签名称出现?
因此,如您所知,JavaScript 的严格模式对标识符 eval
和 arguments
增加了限制,有效地使它们成为保留字,但有两个例外:
So, as you may know, the strict mode of JavaScript adds restrictions on the identifiers eval
, and arguments
, effectively making them reserved words, with two exceptions:
- 它们仍然可以用作表达式,即在需要表达式的地方(但有几个例外),
- 它们仍然可以用作标签名称,并在
break
/continue
语句中引用标签.
- they can still be uses as expressions, i.e. in places where an expression is expected (with a couple of exceptions, though),
- they can still be used as label names, and in
break
/continue
statements to reference labels.
现在,我明白了第一点.例如,如果标识符 eval
不允许作为表达式(而真正的保留字不允许),我们将无法调用 eval
函数根本没有(因为 eval(str)
是一个表达式).arguments
也是如此——我们需要能够将其用作表达式以便能够访问其元素(例如 arguments[0]
).
Now, I understand the first bullet. If, for instance, the identifier eval
wasn't allowed as an expression (and true reserved words aren't), we wouldn't be able to invoke the eval
function at all (since eval(str)
is an expression). Same goes for arguments
- we need to be able to use it as an expression in order to be able to access its elements (e.g. arguments[0]
).
不过,这条规则有三个例外.eval
/arguments
可能不会出现 (1) 作为赋值中的左侧表达式(例如 eval = true;
),(2)作为++
/--
的操作数(例如 eval++
),(3)作为 delete
的操作数(例如 删除评估).不过,这些是唯一的例外,并且在所有其他表达式上下文中,它们都是有效的.
This rule has a three exceptions, though. eval
/arguments
may not appear (1) as left-hand side expressions in assignments (e.g. eval = true;
), (2) as operands of ++
/--
(e.g. eval++
), (3) as operands of delete
(e.g. delete eval
). Those are the only exceptions though, and in all other expression-contexts, they are valid.
我不明白的是第二个子弹.为什么它们仍然可以用作标签名称?例如,即使在严格模式下,这段代码也是有效的:
What I don't understand is the second bullet. Why can they be still used as label names? For instance, this code is valid even in strict mode:
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
函数无关.
Notice how continue eval;
references the eval
label, and has nothing to do with the actual eval
function.
另外,请注意如何将真正的保留字不能用作标签名称.根据我的理解,严格模式的目的是使名称 eval
和 arguments
尽可能类似于保留字.那么为什么要将它们保留为有效的标签名称呢?
Also, notice how true reserved words cannot be used as label names. From my understanding, the intend of strict mode was to make the names eval
, and arguments
as reserved-word-like as possible. Then why keep them as valid label names?
我不知道为什么,但我可以大胆猜测一下.
I don't know why, but I can hazard a pretty good guess.
eval
和 arguments
被限制用于变量名的原因(以及,就此而言,为什么 with
被禁止)是它们影响其中变量名绑定(即绑定到局部变量、封闭范围内的变量或全局对象上的属性(如果存在).如果没有这些限制,某些名称在运行时之前是未绑定的,并带有所有隐含的危险.
The reason eval
and arguments
are restricted for variable names (and, for that matter, why with
is forbidden) is that they affect where variable names bind (i.e. to a local variable, a variable in an enclosing scope, or to a property on the global object if one exists). Without those restrictions, some names are unbound until runtime, with all the hazards that implies.
标签名称与变量名称、属性名称等占据不同的命名空间.break
/continue
的目标永远不会有歧义,因为标签是静态分配的,标签引用是静态解析的.(是的,eval
代码可以包含标签.但是现有的跳转不能针对这些标签,eval
代码中的跳转也不能针对预先存在的标签,因为标签解析发生在编译时,它的范围是程序,使用 ECMAScript 终端的名称.包含 eval
调用的脚本是程序,并且由 eval
执行的代码call 是一个程序,但出于标签定位的目的,两者是完全分开的.)
Label names occupy a different naming space from variable names, property names, and so on. There's never ambiguity about the target of a break
/continue
, because labels are statically assigned and label references are statically resolved. (Yes, eval
code can include labels. But existing jumps can't target those labels, nor can jumps in eval
code target pre-existing labels, because label resolution occurs at compile time, and it is scoped to a Program, to use the ECMAScript terminal's name. A script that contains an eval
call is a Program, and the code executed by the eval
call is a Program, but the two are entirely separate for label-targeting purposes.)
禁止对变量名称使用 eval
和 arguments
的原因根本不适用于标签.因此,标签仍然可以命名为 eval
或 arguments
.以这种方式命名标签是愚蠢的,真的.如果有人再次设计 ECMAScript/JavaScript,它们将是关键字,不能用作标签名称.但是禁止它们作为标签名称并没有任何好处,并且至少有一个小的兼容性参数不禁止它们,所以它们没有被禁止.
The reason to forbid eval
and arguments
for variable names simply doesn't apply to labels. Therefore, labels can still be named eval
or arguments
. It would be stupid to name a label that way, true. And if someone were designing ECMAScript/JavaScript again, they'd be keywords, and not usable as label names. But there's no gain to be had from forbidding them as label names, and at least a small compatibility argument for not forbidding them, so they were not forbidden.