在switch / case语句中,JavaScript变量的作用域是什么?

11

在使用ASP.NET MVC创建JavaScript时,我注意到出现了几个作用域警告,并意识到我缺乏理解switch / case语句内变量作用域的知识。

警告:'i'已经定义 与case b和case c有关

我的代码类似于这样:

switch(element) {
  case 'a':
   for(var i=0; i < count; i++){
    do something
   }
   break;

  case 'b':
   for(var i=0; i < count; i++){
    do something
   }
   break;

  case 'c':
   for(var i=0; i < count; i++){
    do something
   }
   break;
}

我原以为在每个break语句处作用域都会结束,但似乎作用域直到switch/case结束才会结束。那么作用域是否是整个switch/case都适用呢?


我原以为每个break语句会结束作用域,但似乎作用域要一直持续到switch/case语句的结尾。那么作用域是在整个switch/case语句中生效的吗?
3个回答

16

来自MDN文档"casedefault子句不会创建词法作用域。"

因此,在switch语句中声明的所有变量都在同一作用域内。使用相同名称使用let/const声明变量将抛出错误。

switch(someVar) {
    case 1:
        let a;
        break;
    case 2:
        let a; // Uncaught SyntaxError: Identifier 'a' has already been declared
        break;
}

如果你想在 case 子句中创建一个单独的(嵌套的)块作用域,你可以使用 labels

switch(someVar) {
    case 1: { // <- creates a new block scope
        let a;
        break;
    }
    case 2: { // <- creates a new block scope
        let a; 
        break;
    }
}

据我所知,没有一种类似于C语言的编程语言,其中每个case语句都形成一个独立的作用域。

例如,下面的C#代码也无法编译:

switch(someVar) {
    case 1:
        int a;
        break;
    case 2:
        int a;        // 'a' is already defined
        break;
}

是的。我可能在这个问题上犯困了,因为乍一看它似乎是正确的。但是编译器警告让我知道我已经犯困了,真是感谢您提供如此好的答案。 - Todd Moses
4
请注意,在类 C 的编程语言中(不包括 Javascript),如果需要的话,可以在 case 语句后自己创建一个作用域:case 1: { ... } - hugomg
值得一提的是,现在ES6语法允许块级作用域,因此在case后创建作用域是可行的。 - Jason Tavarez
1
请注意,尽管JS现在存在块级作用域,但case默认情况下仍不会创建自己的作用域。例如,在不同的连续case中使用let关键字将引发错误。 - Guy

4

switch/case的作用域是整个函数吗?

不是,它是整个包含函数的作用域,如果你在函数外部,则为全局作用域。

(JavaScript 有少数几种模糊情况会引入额外的作用域,但也仅限于此。)

警告:'i' 已经被定义

我并不认同这是一个警告。我更愿意保留代码中每个块对变量 i 的独立使用。

它想让你做的是,在除第一个声明之外的所有声明中删除 var,或者在 switch 前面添加 var i 并从所有的 for 中删除 var。但现在这些块不再是独立的了,快速剪切和粘贴(例如将 switch 重构为单独的 function)会让你的循环引用一个未声明为 vari。这是一种意外的全局变量,是 JavaScript 中的一个可怕陷阱,可能会非常难以调试。

JSLint 也会发出同样的警告。我通常会忽略它。在一个块中两次声明变量 var 不会造成任何伤害。


是的,我知道它可以工作。但是我不喜欢在生产代码中出现警告。但是办公室里的一次讨论揭示了jQuery也会做同样的事情。所以我可能会放弃修改。感谢您的好回答。 - Todd Moses

0
即使 JavaScript 有块级作用域,也会存在 fall-through 特性,这种情况有点使每个 case 拥有作用域的概念失效...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接