Ответ 1
Когда я посмотрел на решения в других ответах, я увидел, что некоторые вещи, которые, как я знаю, плохи для производительности. Я собирался помещать их в комментарий, но я подумал, что лучше сравнить его и поделиться результатами. Вы можете протестировать его самостоятельно. Ниже приведены мои результаты (ymmv), нормализованные после самой быстрой операции в каждом браузере (умножьте время 1.0 с нормализованным значением, чтобы получить абсолютное время в мс).
Chrome Firefox Opera MSIE Safari Node ------------------------------------------------------------------- 1.0 time 37ms 73ms 68ms 184ms 73ms 21ms 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
Проверьте, где выполняется на Windows 7 32bit с последующими версиями: Chrome 21.0.1180.89m, Firefox 15.0, Opera 12.02, MSIE 9.0.8112, Safari 5.1.7. Node был запущен на 64-битной коробке Linux, потому что разрешение таймера на Node.js для Windows составляло 10 мс вместо 1 мс.
, если немедленное
Это самый быстрый во всех тестируемых средах, за исключением... drumroll MSIE! (Сюрприз Сюрприз). Это рекомендуемый способ его реализации.
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else
, если косвенная
Это вариант switch-indirect-array
, но вместо if
-statements и выполняется намного быстрее, чем 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
включение немедленной
Это довольно быстро во всех тестируемых средах и на самом деле самый быстрый в MSIE. Он работает, когда вы можете сделать расчет, чтобы получить индекс.
switch (Math.floor(val/1000)) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
Переключатель диапазона
Это примерно в 6-40 раз медленнее, чем самая быстрая во всех тестируемых средах, кроме для Opera, где требуется около полутора раз. Он медленный, потому что двигатель должен сравнивать значение дважды для каждого случая. Удивительно, что Chrome почти в 40 раз больше, чем для самой быстрой работы в Chrome, а MSIE - только в 6 раз. Но фактическая разница во времени составила всего 74 мс в пользу MSIE на 1337 мс (!).
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;
}
включение range2
Это вариант switch-range
, но с одним сравнением в каждом случае и, следовательно, быстрее, но все же очень медленный, за исключением Opera. Порядок аргумента case важен, поскольку двигатель проверяет каждый случай в порядке исходного кода ECMAScript262: 5 12.11
switch (true) {
case (val < 1000): /* do something */ break;
case (val < 2000): /* do something */ break;
...
case (val < 30000): /* do something */ break;
}
включение косвенного массива
В этом варианте диапазоны хранятся в массиве. Это медленное во всех тестируемых средах и очень медленное в 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;
}
массив линейно-поиск
Это комбинация линейного поиска значений в массиве, а переключатель с фиксированными значениями. Причина, по которой вы захотите использовать это, - это когда значения не известны до времени выполнения. Он медленный в каждой тестируемой среде и занимает почти 10 раз в MSIE.
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-linear-switch
, но с бинарным поиском.
К сожалению, он медленнее, чем линейный поиск. Я не знаю, является ли это моей реализацией или оптимизирован линейный поиск. Также может быть, что пространство ключей мало.
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
с немедленными значениями.