switch
让我们简单探索一下switch
语句,某种if..else if..else..
语句链的语法缩写。
switch (a) {
case 2:
// 做一些事
break;
case 42:
// 做另一些事
break;
default:
// 这里是后备操作
}
如你所见,它对a
求值一次,然后将结果值与每个case
表达式进行匹配(这里只是一些简单的值表达式)。如果找到一个匹配,就会开始执行那个匹配的case
,它将会持续执行直到遇到一个break
或者遇到switch
块儿的末尾。
这些可能不会令你吃惊,但是关于switch
,有几个你以前可能从没注意过的奇怪的地方。
首先,在表达式a
和每一个case
表达式之间的匹配与===
算法(见第四章)是相同的。switch
经常在case
语句中使用绝对值,就像上面展示的,因此严格匹配是恰当的。
然而,你也许希望允许宽松等价(也就是==
,见第四章),而这么做你需要“黑”一下switch
语句:
var a = "42";
switch (true) {
case a == 10:
console.log( "10 or '10'" );
break;
case a == 42:
console.log( "42 or '42'" );
break;
default:
// 永远不会运行到这里
}
// 42 or '42'
这可以工作是因为case
子句可以拥有任何表达式(不仅是简单值),这意味着它将用这个表达式的结果与测试表达式(true
)进行严格匹配。因为这里a == 42
的结果为true
,所以匹配成功。
尽管==
,switch
的匹配本身依然是严格的,在这里是true
和true
之间。如果case
表达式得出truthy的结果而不是严格的true
,它就不会工作。例如如果在你的表达式中使用||
或&&
这样的“逻辑操作符”,这就可能咬到你:
var a = "hello world";
var b = 10;
switch (true) {
case (a || b == 10):
// 永远不会运行到这里
break;
default:
console.log( "Oops" );
}
// Oops
因为(a || b == 10)
的结果是"hello world"
而不是true
,所以严格匹配失败了。这种情况下,修改的方法是强制表达式明确成为一个true
或false
,比如case !!(a || b == 10):
(见第四章)。
最后,default
子句是可选的,而且它不一定非要位于末尾(虽然那是一种强烈的惯例)。即使是在default
子句中,是否遇到break
的规则也是一样的:
var a = 10;
switch (a) {
case 1:
case 2:
// 永远不会运行到这里
default:
console.log( "default" );
case 3:
console.log( "3" );
break;
case 4:
console.log( "4" );
}
// default
// 3
注意: 就像我们前面讨论的打标签的break
,case
子句内部的break
也可以被打标签。
这段代码的处理方式是,它首先通过所有的case
子句,没有找到匹配,然后它回到default
子句开始执行。因为这里没有break
,它会继续走进已经被跳过的块儿case 3
,在遇到那个break
后才会停止。
虽然这种有些迂回的逻辑在JavaScript中是明显可能的,但是它几乎不可能制造出合理或易懂的代码。要对你自己是否想要创建这种环状的逻辑流程保持怀疑,如果你真的想要这么做,确保你留下了大量的代码注释来解释你要做什么!