所以我想用这样的switch语句:
switch (scrollLeft) {
case (<1000):
//do stuff
break;
case (>1000 && <2000):
//do stuff
break;
}
现在我知道这些语句(<1000)或(>1000 && <2000)中的任何一个都不会工作(显然是由于不同的原因)。我问的是最有效的方法。我讨厌使用30个if语句,所以我宁愿使用switch语法。我能做些什么吗?
所以我想用这样的switch语句:
switch (scrollLeft) {
case (<1000):
//do stuff
break;
case (>1000 && <2000):
//do stuff
break;
}
现在我知道这些语句(<1000)或(>1000 && <2000)中的任何一个都不会工作(显然是由于不同的原因)。我问的是最有效的方法。我讨厌使用30个if语句,所以我宁愿使用switch语法。我能做些什么吗?
当前回答
我讨厌使用30个if语句
我最近也遇到了同样的情况,我是这样解决的:
之前:
if(wind_speed >= 18) {
scale = 5;
} else if(wind_speed >= 12) {
scale = 4;
} else if(wind_speed >= 9) {
scale = 3;
} else if(wind_speed >= 6) {
scale = 2;
} else if(wind_speed >= 4) {
scale = 1;
}
后:
var scales = [[4, 1], [6, 2], [9, 3], [12, 4], [18, 5]];
scales.forEach(function(el){if(wind_speed > el[0]) scale = el[1]});
如果你设置“1、2、3、4、5”,那么它可以更简单:
var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
其他回答
更新已接受的答案(还不能评论)。截至2016年1月12日在chrome中使用演示jsfiddle, switch-immediate是最快的解决方案。
结果: 时间分辨率:1.33
25ms "if-immediate" 150878146
29ms "if-indirect" 150878146
24ms "switch-immediate" 150878146
128ms "switch-range" 150878146
45ms "switch-range2" 150878146
47ms "switch-indirect-array" 150878146
43ms "array-linear-switch" 150878146
72ms "array-binary-switch" 150878146
完成了
1.04 ( 25ms) if-immediate
1.21 ( 29ms) if-indirect
1.00 ( 24ms) switch-immediate
5.33 ( 128ms) switch-range
1.88 ( 45ms) switch-range2
1.96 ( 47ms) switch-indirect-array
1.79 ( 43ms) array-linear-switch
3.00 ( 72ms) array-binary-switch
当我查看其他答案中的解决方案时,我看到了一些我知道对性能不利的东西。我打算把它们放在评论中,但我认为最好是基准测试并分享结果。你可以自己测试。下面是我的结果(ymmv)在每个浏览器中最快的操作后归一化。
以下是2021年5月-05日的结果
Test | Chrome | Firefox | Opera | Edge | Brave | Node |
---|---|---|---|---|---|---|
1.0 time | 15 ms | 14 ms | 17 ms | 17 ms | 16 ms | 14 ms |
if-immediate | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
if-indirect | 2.20 | 1.21 | 2.06 | 2.18 | 2.19 | 1.93 |
switch-immediate | 2.07 | 1.43 | 1.71 | 1.71 | 2.19 | 1.93 |
switch-range | 3.60 | 2.00 | 2.47 | 2.65 | 2.88 | 2.86 |
switch-range2 | 2.07 | 1.36 | 1.82 | 1.71 | 1.94 | 1.79 |
switch-indirect-array | 2.93 | 1.57 | 2.53 | 2.47 | 2.75 | 2.50 |
array-linear-switch | 2.73 | 3.29 | 2.12 | 2.12 | 2.38 | 2.50 |
array-binary-switch | 5.80 | 6.07 | 5.24 | 5.24 | 5.44 | 5.37 |
2021年的测试在Windows 10 64bit上进行,版本如下:Chrome 90.0.4430.212, Firefox 80.9 b13, Opera 76.0.4017.123, Edge 90.0.818.62, Brave 1.24.85和Node 16.1.0(在WSL下运行)
苹果没有针对Windows更新Safari,所以它仍然是5.1.7版本。我在这次测试中把它改成了Brave。
以下是2012年9月至2004年的结果,用于历史比较:
Test | Chrome | Firefox | Opera | MSIE | Safari | Node |
---|---|---|---|---|---|---|
1.0 time | 37 ms | 73 ms | 68 ms | 184 ms | 73 ms | 21 ms |
if-immediate | 1.0 | 1.0 | 1.0 | 2.6 | 1.0 | 1.0 |
if-indirect | 1.2 | 1.8 | 3.3 | 3.8 | 2.6 | 1.0 |
switch-immediate | 2.0 | 1.1 | 2.0 | 1.0 | 2.8 | 1.3 |
switch-range | 38.1 | 10.6 | 2.6 | 7.3 | 20.9 | 10.4 |
switch-range2 | 31.9 | 8.3 | 2.0 | 4.5 | 9.5 | 6.9 |
switch-indirect-array | 35.2 | 9.6 | 4.2 | 5.5 | 10.7 | 8.6 |
array-linear-switch | 3.6 | 4.1 | 4.5 | 10.0 | 4.7 | 2.7 |
array-binary-switch | 7.8 | 6.7 | 9.5 | 16.0 | 15.0 | 4.9 |
2012年的测试在Windows 7 32位上进行,版本如下:Chrome 21.0.1180.89m, Firefox 15.0, Opera 12.02, MSIE 9.0.8112, Safari 5.1.7。Node运行在Linux 64位机器上,因为Node for Windows上的计时器分辨率是10ms而不是1ms。
眼前的
这是所有测试环境中最快的方法,除了……击鼓MSIE !(震惊)。
这是推荐的实现方法。
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else
虽然是间接的
这是switch-indirect-array的变体,但是使用if语句代替,并且在所有测试引擎中都更快。
2021年比最快的测试慢了20-120%(2012年:0-280%)。2021年Chrome浏览器使用时间(2.20)比2012年(1.2)更长
values=[
1000, 2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else
switch-immediate
当您可以通过计算来获得索引时,这种方法是有效的。
在2021年,它比if-immediate慢了40-120%(2012年:0-180%),除了在MSIE中它实际上是最快的。
switch (Math.floor(val/1000)) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
量程切换
它很慢,因为引擎必须对每种情况的值进行两次比较。
在2021年,它比最快的测试慢了1-2.6倍(2012年:1.6-38倍)。 Chrome从38到3.6的进步最大,但仍然是测试中最慢的引擎。
switch (true) {
case (0 <= val && val < 1000): /* do something */ break;
case (1000 <= val && val < 2000): /* do something */ break;
...
case (29000 <= val && val < 30000): /* do something */ break;
}
switch-range2
这是switch-range的变体,但每个情况只有一个比较,因此更快。 case语句的顺序很重要,因为引擎将按照源代码顺序ECMAScript 2020 13.12.9测试每个case
在2021年,它比最快的测试慢了36-107%,但在2012年,它慢了1-31倍。在这次测试中,Chrome仍然是表现最差的,但它已经从32倍提高到了2倍。
switch (true) {
case (val < 1000): /* do something */ break;
case (val < 2000): /* do something */ break;
...
case (val < 30000): /* do something */ break;
}
switch-indirect-array
在这个变体中,范围存储在一个数组中。
在2021年,比最快的测试慢了57-193%(2012年:3-35倍)。 所有测试引擎的性能都有所提高,虽然Chrome仍然是最慢的,但它已经从35提升到了2.93。
values=[1000, 2000 ... 29000, 30000];
switch(true) {
case (val < values[0]): /* do something */ break;
case (val < values[1]): /* do something */ break;
...
case (val < values[29]): /* do something */ break;
}
array-linear-search
在这个变体中,范围存储在一个数组中。
在2021年,比最快的测试慢了57-193%(2012年:3-35倍)。 所有测试引擎的性能都有所提高,虽然Chrome仍然是最慢的,但它已经从35提升到了2.93。
values=[1000, 2000 ... 29000, 30000];
for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
if (val < values[sidx]) break;
}
switch (sidx) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
array-binary-switch
这是数组-线性切换的一种变体,但带有二进制搜索。 不幸的是,它比线性搜索慢。我不知道这是我的实现还是线性搜索更优化。也可能是密钥空间太小了。
到2021年,这一数字下降了4-5倍(2012年为4-16倍)。不要使用。
values=[0, 1000, 2000 ... 29000, 30000];
while(range) {
range = Math.floor( (smax - smin) / 2 );
sidx = smin + range;
if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}
switch (sidx) {
case 0: /* do something */ break;
...
case 29: /* do something */ break;
}
结论
如果性能很重要,使用If语句或switch,并带有立即值。
未经测试,不确定这是否会工作,但为什么不做一些if语句之前,为switch语句设置变量。
var small, big;
if(scrollLeft < 1000){
//add some token to the page
//call it small
}
switch (//reference token/) {
case (small):
//do stuff
break;
case (big):
//do stuff;
break;
}
在我的例子中(用颜色编码百分比,没有任何性能关键),我很快写下了这样的内容:
function findColor(progress) {
const thresholds = [30, 60];
const colors = ["#90B451", "#F9A92F", "#90B451"];
return colors.find((col, index) => {
return index >= thresholds.length || progress < thresholds[index];
});
}
switch (Math.floor(scrollLeft/1000)) {
case 0: // (<1000)
//do stuff
break;
case 1: // (>=1000 && <2000)
//do stuff;
break;
}
只有当你有规律的步数时才有效……
编辑:由于这个解决方案不断得到点赞,我必须建议mofolo的解决方案是一个更好的方式