我想像这样使用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语法。我能做些什么吗?测试 | Chrome | Firefox | Opera | Edge | Brave | Node |
---|---|---|---|---|---|---|
1.0 时间 | 15 毫秒 | 14 毫秒 | 17 毫秒 | 17 毫秒 | 16 毫秒 | 14 毫秒 |
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 |
测试 | Chrome | Firefox | Opera | MSIE | Safari | Node |
---|---|---|---|---|---|---|
1.0 时间 | 37 毫秒 | 73 毫秒 | 68 毫秒 | 184 毫秒 | 73 毫秒 | 21 毫秒 |
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 |
在所有测试环境中,这是最快的方法,除了... 鼓声响起 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%)。Chrome在2021年(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
当你可以进行计算以获得索引时,这个方法适用。
在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-range
的一个变体,但每个case只有一个比较,因此速度更快。
case语句的顺序很重要,因为引擎会按照源代码的顺序测试每个case ECMAScript 2020 13.12.9
在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;
}
在这个变体中,范围被存储在一个数组中。
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;
}
在这个变种中,范围被存储在一个数组中。
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;
}
这是数组线性开关
的一个变种,但使用了二进制搜索。
不幸的是,它比线性搜索要慢。我不知道是我的实现有问题还是线性搜索更加优化。也有可能是键空间太小。
在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
语句,使用立即值。
另一种选择:
var scrollleft = 1000;
switch (true)
{
case (scrollleft > 1000):
alert('gt');
break;
case (scrollleft <= 1000):
alert('lt');
break;
}
if(...) else if(...)
一样吗?虽然避免了 if
,但我觉得并不是很优雅的替代方式。 - pimvdbswitch (Math.floor(scrollLeft/1000)) {
case 0: // (<1000)
//do stuff
break;
case 1: // (>=1000 && <2000)
//do stuff;
break;
}
只有在步长规则是固定的情况下才有效...
编辑:由于这个解决方案不断获得赞,我必须提醒mofolo的解决方案更好。
Math.round(scrollLeft/1000)
。 - switzvar rules = [{ lowerLimit: 0, upperLimit: 1000, action: function1 }, { lowerLimit: 1000, upperLimit: 2000, action: function2 }, { lowerLimit: 2000, upperLimit: 3000, action: function3 }];
针对这些情况,定义相应的函数(如定义function1、function2等)
并"评估"规则
function applyRules(scrollLeft)
{
for(var i=0; i>rules.length; i++)
{
var oneRule = rules[i];
if(scrollLeft > oneRule.lowerLimit && scrollLeft < oneRule.upperLimit)
{
oneRule.action();
}
}
}
注意
我讨厌使用30个if语句。
很多时候,使用if语句更易于阅读和维护。我建议只有当您有很多条件并且未来可能出现很多增长的情况下,才使用以上建议。
更新
正如@Brad在评论中指出的那样,如果条件是互斥的(每次只能为真),则检查上限就足够了:
if(scrollLeft < oneRule.upperLimit)
action=function1
-- 这不应该是冒号吗?;-) -- 你也可以重构它,只设置一个上限,因为通过排除法,你不能落在两个组之间--除非你的意图是这样做(允许多个操作)。 - Brad Christie你在//做一些事情
方面具体在做什么?
可能你可以像下面这样做:
(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc.
switch (true) {
case (value > 100):
//do stuff
break;
case (value <= 100)&&(value > 75):
//do stuff
break;
case (value < 50):
//do stuff
break;
}
没有经过测试,不确定这是否有效,但在使用switch语句
之前,为了设置变量,可以进行一些if语句
。
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;
}
更新被接受的答案(目前无法评论)。截至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
function findColor(progress) {
const thresholds = [30, 60];
const colors = ["#90B451", "#F9A92F", "#90B451"];
return colors.find((col, index) => {
return index >= thresholds.length || progress < thresholds[index];
});
}
我讨厌使用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]});
var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
your_mapper_object[scrollLeft / SOME_CONST]
,假设your_mapper_object
类似于{1: some_func, 2: another_func, ...}
。而且在这种情况下,也可以使用 switch。 - Overmind Jiang