所以我想用这样的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的解决方案是一个更好的方式