在对标记语句的行为进行了一些调查之后,我认为这实际上只是 Crockford 的一个选择,实际上并没有真正的依据。据我所知,没有任何情况会导致与全局范围内的标签发生命名冲突(这似乎是人们想到 JSLint 不允许它的主要原因 - 请参阅有关问题的评论)。
ES5 规范在标记语句的部分中声明了以下内容:
产生式Identifier : Statement通过将
Identifier添加到Statement的标签集然后评估Statement来评估。
...
在评估LabelledStatement之前,包含的Statement被认为拥有一个空标签集,除非它是IterationStatement或SwitchStatement,在这种情况下,它被认为拥有由单个元素组成的标签集empty
。
我认为这意味着每个语句都有一个标签集。标签标识符独立于变量和函数标识符,因此在语法上可以接受与同一范围内的变量具有相同标识符的标签。换句话说,这是有效的:
var label = "My Label";
label:
for (var x = 1; x < 10; x++) {
break label;
}
由于每个语句都有自己的标签集,因此这也是有效的:
label:
for (var x = 1; x < 10; x++) {
//Looks for 'label' in label set of `break` statement, then `for` statement
break label;
}
label:
for (var y = 5; y < 15; y++) {
//Same again. Will never look for label outside the enclosing `for` statement
break label;
}
由于您可以标记任何语句(这毫无意义,但这是可能的),您可以标记一个带标签的语句:
another:
label:
for (var y = 5; y < 15; y++) {
break label;
}
在这种情况下,规范声明如下:
如果LabelledStatement本身有一个非空标签集,这些标签也会在评估之前添加到 Statement 的标签集。
在上面的代码片段中,for
语句的标签集包含两个标签(another
和label
)。可以从语句中拆分为这些标签中的任何一个。for
最后,规范还指出(强调):
带标签的语句仅与带标签的break
和continue
语句一起使用。ECMAScript 没有goto
声明。
因此,基于所有这些,我想不出全局代码中的任何标签干扰其他全局代码的可能方式。当然,您不太可能想要一个包含多个具有相同标识符的标签的程序,而 JSLint 已经通过抛出“标签已定义”错误来防止这种情况发生。但我认为它在全局执行上下文中处理标记语句的方式应该没有任何区别。