Оператор switch для более чем/меньше, чем

поэтому я хочу использовать оператор switch следующим образом:

switch (scrollLeft) {
  case (<1000):
   //do stuff
   break;
  case (>1000 && <2000):
   //do stuff
   break;
}

Теперь я знаю, что любое из этих утверждений (<1000) или (>1000 && <2000) не будет работать (по разным причинам, очевидно). То, что я прошу, - это самый эффективный способ сделать именно это. Я ненавижу использовать 30 if операторов, поэтому я бы предпочел использовать синтаксис switch. Есть ли что-нибудь, что я могу сделать?

Ответ 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 с немедленными значениями.

Ответ 2

Альтернатива:

var scrollleft = 1000;
switch (true)
{
    case (scrollleft > 1000):
      alert('gt');
      break;
    case (scrollleft <= 1000):
      alert('lt');
      break; 
}

Демо: http://jsfiddle.net/UWYzr/

Ответ 3

switch (scrollLeft/1000) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

Работает только если у вас есть регулярные шаги...

РЕДАКТИРОВАТЬ: так как это решение продолжает расти, я должен посоветовать, что решение mofolo является лучшим способом

Ответ 4

Вы можете создать пользовательский объект с критериями и функцией, соответствующей критериям

var rules = [{ lowerLimit: 0,    upperLimit: 1000, action: function1 }, 
             { lowerLimit: 1000, upperLimit: 2000, action: function2 }, 
             { lowerLimit: 2000, upperLimit: 3000, action: function3 }];

Определите функции для того, что вы хотите сделать в этих случаях (определите функцию1, 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

Много раз, если утверждения легче читать и поддерживать. Я бы рекомендовал вышесказанное только тогда, когда у вас много условий и возможностей для роста в будущем.

Обновление
Как отметил @Brad в комментариях, если условия взаимоисключающие (только один из них может быть истинным за раз), проверка верхнего предела должна быть достаточной:

if(scrollLeft < oneRule.upperLimit)

при условии, что условия определены в порядке возрастания (сначала самый низкий, 0 to 1000, а затем 1000 to 2000 например)

Ответ 5

Неподтвержденный и неуверенный, если это будет работать, но почему бы не сделать несколько if statements раньше, чтобы установить переменные для switch statement.

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;
}

Ответ 6

Что именно вы делаете в //do stuff?

Вы можете сделать что-то вроде:

(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc. 

Ответ 7

В моем случае (цветовое кодирование в процентах, без критического значения) я быстро написал это:

function findColor(progress) {
    const thresholds = [30, 60];
    const colors = ["#90B451", "#F9A92F", "#90B451"];

    return colors.find((col, index) => {
        return index >= thresholds.length || progress < thresholds[index];
    });
}

Ответ 8

Это еще один вариант:

     switch (true) {
         case (value > 100):
             //do stuff
             break;
         case (value <= 100)&&(value > 75):
             //do stuff
             break;
         case (value < 50):
            //do stuff
             break;
     }

Ответ 9

Обновление принятого ответа (не могу комментировать). Начиная с 1/12/16 с помощью демонстрационного jsfiddle в chrome, switch-instant является самым быстрым решением.

Результаты: Разрешение по времени: 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