切换语句大于/小于
所以我想用这样的switch语句:
switch (scrollLeft) { case (<1000): //do stuff break; case (>1000 && <2000): //do stuff break; }
现在我知道这些语句( <1000
)或( >1000 && <2000
)中的任何一个都不起作用(显然是出于不同的原因)。 我所要求的是最有效的方法。 我讨厌使用30条if
语句,所以我宁愿使用switch语法。 有什么我能做的吗?
当我在其他答案中看到解决scheme时,我看到了一些我知道对性能不好的东西。 我将要发表评论,但是我认为最好是对它进行基准testing并分享结果。 你可以自己testing一下 。 下面是我的结果(ymmv)在每个浏览器中最快的操作之后归一化(将1.0倍的时间乘以归一化的值以绝对时间为单位)。
Chrome Firefox Opera MSIE Safari节点 -------------------------------------------------- ----------------- 1.0次37ms 73ms 68ms 184ms 73ms 21ms if-immediate 1.0 1.0 1.0 2.6 1.0 1.0 如果 - 间接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 开关范围38.1 10.6 2.6 7.3 20.9 10.4 开关范围2 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 arrays线性开关3.6 4.1 4.5 10.0 4.7 2.7 arrays二进制开关7.8 6.7 9.5 16.0 15.0 4.9
testing在Windows 7 32位上执行以下版本: Chrome 21.0.1180.89m , Firefox 15.0 , Opera 12.02 , MSIE 9.0.8112 , Safari 5.1.7 。 节点运行在Linux 64位盒子上,因为Node.js for Windows上的计时器分辨率是10ms而不是1ms。
如果,即时
这是所有testing环境中速度最快的,除了… drumroll MSIE! (惊喜,惊喜)。 这是实施它的推荐方法。
if (val < 1000) { /*do something */ } else if (val < 2000) { /*do something */ } else ... if (val < 30000) { /*do something */ } else
如果间接
这是switch-indirect-array
一个变体,但是在if
语句的情况下,在几乎所有的testing环境中,它的执行速度要比switch-indirect-array
快得多。
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
开关,立即
这在所有testing环境中都非常快,实际上是MSIE中速度最快的。 它可以工作,当你可以做一个计算来获得索引。
switch (Math.floor(val/1000)) { case 0: /* do something */ break; case 1: /* do something */ break; ... case 29: /* do something */ break; }
开关范围
这比所有testing环境中最快的速度慢了6到40倍,除了Opera,大约需要一倍半的时间。 这很慢,因为引擎必须比较两个值的情况。 令人惊讶的是,与Chrome上运行速度最快的操作系统相比,Chrome的运行速度要快40倍,而MSIE只能运行6次。 但在1337ms(!),实际的时差仅为74ms,有利于MSIE。
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; }
开关范围2
这是一个switch-range
的变体,但每个案件只有一个比较,因此速度更快,但除Opera以外仍然非常缓慢。 case语句的顺序很重要,因为引擎会以源代码的顺序testing每个case ECMAScript262:12.11
switch (true) { case (val < 1000): /* do something */ break; case (val < 2000): /* do something */ break; ... case (val < 30000): /* do something */ break; }
切换-间接arrays
在这个变体中,范围被存储在一个数组中。 这在所有testing环境中都很慢,而且在Chrome中很慢。
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; }
arrays线性search
这是一个线性search数组中值的结合,以及具有固定值的开关语句。 人们可能想要使用它的原因是直到运行时才知道这些值。 它在每个testing环境中都很慢,而且在MSIE中要花费近10倍的时间。
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; }
arrays二进制开关
这是一个array-linear-switch
的变体,但是具有二进制search。 不幸的是它比线性search慢。 我不知道这是我的实现还是线性search更加优化。 它也可能是密钥空间很小。
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
-statements或使用即时值进行switch
。
替代:
var scrollleft = 1000; switch (true) { case (scrollleft > 1000): alert('gt'); break; case (scrollleft <= 1000): alert('lt'); break; }
演示: http : //jsfiddle.net/UWYzr/
switch (scrollLeft/1000) { case 0: // (<1000) //do stuff break; case 1: // (>=1000 && <2000) //do stuff; break; }
只有当你有规律的步骤
编辑:因为这个解决scheme不断得到upvotes,我必须build议, mofolo的解决scheme是一个更好的方法
您可以使用与标准对应的标准和function创build自定义对象
var rules = [{ lowerLimit: 0, upperLimit: 1000, action: function1 }, { lowerLimit: 1000, upperLimit: 2000, action: function2 }, { lowerLimit: 2000, upperLimit: 3000, action: function3 }];
在这些情况下定义你想要做的function(定义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条语句
很多时候,如果陈述更容易阅读和维护。 只有当你有很多的条件和未来有很大的增长的可能性,我才会推荐以上。
更新
正如@Brad在评论中指出的那样,如果条件是相互排斥的(一次只能有一个是真的),那么检查上限就足够了:
if(scrollLeft < oneRule.upperLimit)
条件是按升序定义(例如,首先是最低的一个,例如0 to 1000
,然后是1000 to 2000
)
未经testing和不确定这是否可行,但为什么不做一些if statements
之前,为switch statement
设置variables。
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; }
你到底在//do stuff
?
您可能可以执行如下操作:
(scrollLeft < 1000) ? //do stuff : (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff : (scrollLeft > 2000) ? //do stuff : //etc.
在我的情况下(颜色编码的百分比,没有性能关键),我很快写了这样的:
function findColor(progress) { const thresholds = [30, 60]; const colors = ["#90B451", "#F9A92F", "#90B451"]; return colors.find((col, index) => { return index >= thresholds.length || progress < thresholds[index]; }); }
这是另一个select:
switch (true) { case (value > 100): //do stuff break; case (value <= 100)&&(value > 75): //do stuff break; case (value < 50): //do stuff break; }
更新接受的答案(不能评论)。 在1/12/16使用chrome中的demo jsfiddle,switch-immediate是最快的解决scheme。
结果:时间分辨率: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