本文深入解析JavaScript中if与switch的执行机制,指出switch内部使用全等比较且无类型转换。同时探讨==与===的区别,通过字符串内存池机制解释全等判断相等的底层原因,并提供if语句多层嵌套的性能优化建议。
switch内部比较机制与性能探讨
在修改BoxScroll插件时,由于if条件分支超过两个,考虑改用switch语句。此时联想到JSHint等代码质量检查工具的建议:使用===替代==,以避免不可靠的强制类型转换。由此产生疑问:改用switch是否会降低执行效率?switch内部实际使用的是==还是===进行比较?
为了验证上述猜想,进行如下测试:
var a = '5';
switch (a) {
case 5:
console.log('==');
break;
case "5":
console.log('===');
break;
default:
}
控制台输出结果显示为===,说明switch内部确实使用全等运算符进行比较,可以放心使用。查阅之前的学习笔记发现,高三教程中也明确指出switch判断采用全等运算符,不会发生类型转换。
if与switch的执行逻辑与优化
1. if和switch
if是使用频率最高的控制流语句。需要注意的是,if的行为与||运算符相似:当if (conditionA){} else {}中的conditionA为true时,执行完if块后直接跳过else块,即使else块中存在错误也不会执行。这与||运算符在左侧为true时忽略右侧的逻辑一致。基于此特性,应将最可能执行的代码块置于前面,以减少判断次数。另一方面,若存在大量if判断且执行概率分布均匀,后续判断需逐一执行前面的条件,不利于性能优化。
if (a > 0 && a <= 1) {
//do something
} else if (a > 1 && a <= 2) {
} else if (a > 2 && a <= 3) {
} else if (a > 3 && a <= 4) {
} else if (a > 4 && a <= 5) {
} else if (a > 5 && a <= 6) {
}...
优化方案如下:
if (a > 0 && a <= 4) {
if (a <= 1) {
//do something
} else if (a > 1 && a <= 2) {
} else if (a > 2 && a <= 3) {
} else if (a > 3 && a <= 4) {
}
} else if (a > 4 && a <= 8) {
//
}..
虽然每个前置判断增加了一次检查,但后续判断减少了(4-1)*n次,整体性能得到提升。这种分层判断方式与嵌套循环优化类似,将循环次数少的逻辑置于外层有助于提升性能。具体分为两层或多层需根据实际情况调整。
switch是if的补充,当if处理复杂分支时,switch可协助处理。两者可相互转换,且均按顺序从上往下执行判断。与if不同的是,switch不使用else,而是依赖break语句。若未遇到break,switch将继续向下执行,例如:
var a = 2;
switch (a) {
case 1:
console.log("1");
//break miss
case 2:
console.log("2");
case 3:
console.log("3");
default:
console.log('no break');
}
控制台输出结果为 2,3,no break 。这很好理解:break的作用是跳出当前case并进入下一个case判断;若无break,则相当于if(condition){A}{B}且无else,A和B都会执行。
switch (A + B) {
case a * b:
console.log("1");
break;
case a / b + c:
break;
//...
default:
console.log('no break');
}
两个小技巧:首先,switch和case中可编写任意表达式,例如:
switch (true) {
case condition1:
//do something
break;
case condition2:
break;
//...
default:
//..
;
}
此时实际比较的是 (A+B)===(a*b) 和 (A+B)===(a/b+c)。其次,switch还有一种特殊用法:
==与===的区别及字符串内存机制
此时switch中的每个case会按顺序判断并执行。至于switch(false)并无实际用途。
2. ==与===
一句话总结:除了比较前不转换操作数外,全等和不全等操作符与相等和不相等操作符并无其他区别。
var a = "5",
b = 5;
a == b //true
a === b //false
var a = "ABC",
b = "AB" + "C";
a === b //true
上述结果为 true 的原因与 string 类型的不可变性密切相关。表面上看,b 仅是简单拼接字符串,但实际上它已与原 b 无关。每个字符串在内存池中有特定位置,当执行 b="AB"+"C" 后,字符串 AB 和 C 即被销毁,b 指向内存池中 ABC 的位置。由于此前存在变量引用字符串 ABC(由 a 引用,故存在),b 便与 a 指向同一区域,全等判断为相等。若此前无变量指向字符串 ABC,内存池中不存在,则会开辟新空间给 ABC,并将 b 指向 ABC。
控制台输出true的原因与字符串类型的不可变性密切相关。表面看b只是拼接字符串,但实际上它与原b已无关联。每个字符串在内存池中有特定位置,当b="AB"+"C"执行完毕后,字符串AB和C已被销毁,而b指向内存池中ABC的位置。由于a引用着ABC(因此存在),b与a指向同一内存区域,全等判断为相等。若b之前无变量指向ABC,内存池中不存在,则会开辟新区域给ABC,并将b指向该区域。


附两张之前的总结图: