在全局代码中使用带标签的语句有什么问题?

时间:2012-07-17 20:35:55

标签: javascript jslint

我只是在浏览source of JSLint并注意到这段代码:

// Is this a labeled statement?
//...
if (next_token.labeled !== true || funct === global_funct) {
    stop('unexpected_label_a', label);
} //...

有趣的部分是funct === global_funct比较。通过JSLint运行以下代码段会引发“意外标签”错误,因为带标签的语句位于全局执行上下文中(我知道,这是一个愚蠢的例子。Here's a fiddle。):

loop:
for (var i = 0; i < 10; i++) {
    if (i === 5) {
        break loop;
    }
}

如果将相同的片段放在函数中,JSLint对它非常满意,并且在遇到标签时不会抛出错误。 Here's a fiddle代码将传递JSLint。如果您想尝试,可以将代码粘贴到online version of JSLint

所以我的问题是:在全球代码中使用带标签的语句有什么问题,还是Crockford的另一个人选择?

1 个答案:

答案 0 :(得分:3)

在对标签声明的行为进行一些调查后,我认为这实际上只是Crockford的一个选择,实际上并没有真正的基础。据我所知,没有任何情况可能导致与全局范围内的标签发生命名冲突(这似乎是人们可以想到为什么JSLint不允许它的主要原因 - 请参阅有关该问题的评论)。 / p>

ES5规范在section on labelled statements中声明了以下内容:

  

通过添加评估生产标识符:声明   标识符 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语句的标签集包含两个标签(anotherlabel)。可以在for语句中突破 这些标签。

最后,该规范还指出(强调增加):

  

标记语句仅与标记为break的标记一起使用   和continue陈述。 ECMAScript没有goto声明

基于这一切,我无法想到全局代码中的任何标签可能会干扰其他全局代码。当然,您不太可能希望程序包含具有相同标识符的多个标签,并且JSLint已经通过抛出“已定义标签”错误来防止这种情况。但我认为在全局执行环境中如何处理标记语句不应该有任何区别。