2010-08-12 3 views
23

Я пытаюсь создать оператор switch, но я не могу использовать выражение, которое получает оценку (а не заданную строку/целое число). Я могу легко сделать это, если утверждения, но случай, надеюсь, будет быстрее.Выражение внутри оператора case switch

Я пытаюсь следующий

function reward(amount) { 
    var $reward = $("#reward"); 
    switch (amount) { 
     case (amount >= 7500 && amount < 10000): 
      $reward.text("Play Station 3"); 
      break; 
     case (amount >= 10000 && amount < 15000): 
      $reward.text("XBOX 360"); 
      break; 
     case (amount >= 15000): 
      $reward.text("iMac"); 
      break; 
     default: 
      $reward.text("No reward"); 
      break; 
    } 
} 

я упускаю что-то очевидно, или это не возможно? В этом случае Google не был дружелюбен.

Любые помогают/указатели оценили

M

ответ

78

Вы всегда можете сделать

switch (true) { 
    case (amount >= 7500 && amount < 10000): 
    //code 
    break; 
    case (amount >= 10000 && amount < 15000): 
    //code 
    break; 

    //etc... 

Это работает, потому что true является постоянным, так что код под первым оператором случае с выражением, которое оценивается как истина будет выполняться.

Это своего рода «сложный», я думаю, но я не вижу ничего плохого в его использовании. Простое заявление if/else, вероятно, будет более кратким, и вам не придется беспокоиться о случайном провале. Но все равно.

+3

Это лучше, чем ответ, чем «ответ» Дэниелса. С небольшим предупреждением: все выражения до того, что приводит к случаю true, тоже будут оценены. быть осторожен. – 2013-08-19 11:17:04

+1

Да, это работает, потому что вы всегда можете думать о функции переключения, как таблица перехода, она должна только соответствовать и получать значение. Это не похоже на утверждения if else, потому что все, что нужно, нужно оценивать. Вы уже просите свой коммутатор оценить соответствие vs. Вот почему коммутаторы быстрее. – Vontei

+0

@Vontei - Если структура if/else if/else не оценивается, все они оцениваются по очереди только до тех пор, пока не будет выполнено конкретное условие, что является одним и тем же, что происходит при оценке выражений 'case'. – nnnnnn

9

Это не то, как switch блок работает. case используется для хранения единственного значения, если они равны значению на линии switch. if-else заявления послужат вам хорошо.

Вот некоторая информация о блоке switch.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch

+1

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch –

2

Во-первых, это не так, как switch работы. Вы должны указать константы для каждого case, и эти константы будут сравниваться с выражением в круглых скобках (в вашем случае amount). Вот как работает switch, период.

Во-вторых, переключатель не быстрее, чем несколько if s

И в-третьих, вы не должны действительно беспокоиться о мизерных оптимизации производительности, когда вы имеете дело с JavaScript.

+0

Ну, всегда лучше беспокоиться о производительности. Это дает вам место, когда вам нужно что-то делать. – MindlessRanger

+0

* «Вы должны указать константы для каждого случая» * - Нет, вы этого не делаете. Использование констант является наиболее распространенным способом использования 'switch', но вы можете указать любое выражение в каждом« случае », с переменными или вызовами функций или без них, и значение сравнивается. – nnnnnn

1

Проблема заключается в том, что выражение switch не может сравниться с выражениями case, потому что выражение case будет оцениваться как true или false, но выражение switch будет числом.

Решение, в котором выражение switch установлено в true, работает не потому, что true является константой, а потому, что на самом деле возможно равенство с выражениями case.

Неверно, что вы должны указывать константы для каждого выражения case.

Чтобы создать резервную копию моего ответа, обратитесь к Дугласу Crockford, Javascript The Good Parts (2008), страница 12:

Оператор переключателя выполняет многоходовую ветвь.Он сравнивает выражение для равенства со всеми выбранными случаями .... Когда найдено точное совпадение, выполняются инструкции предложения case case ... Предложение case содержит одно или несколько выражений case. Выражения случая не обязательно должны быть константами.

+0

Можно добавить, что оценка блока корпуса выполняется в порядке исходного кода. Сверху вниз. – dotnetCarpenter

8

@ MooGoo-х switch (true) даст вам Weird condition error in jsLint, так что давайте немного более творческий подход в случае, если это вопрос, и, я думаю, повысить читаемость прикосновение.

Таким образом, мы не оцениваем, является ли каждый casetrue или false; мы сравниваем, если это значение case равно нашему термину switch. Так что давайте воспользуемся этим, выбросив стенографию if в наш case заявление и вернем наш первоначальный термин коммутатора, если это условие.

Я также включаю пример реального мира, в котором вы хотите иметь два «значения по умолчанию» - один, если ваш термин находится за пределами вашего «важного» диапазона в положительном направлении, а другой - в отрицательном направлении.

Ключевая фраза: case (x > 0 ? x : null):

«Если мой термин, x, больше нуля, вернуться x так что x === x и я беру случай ветвь.»

http://jsfiddle.net/rufwork/upGH6/1/

/*global document*/ 
/*jslint evil:true*/ 
var x = 10; 

switch (x) { 
    case (x > 0 ? x : null): 
     document.write('ha ha ha! I fooled switch AND jsLint! Muhahahahaha!'); 
     break; 
    case 0: 
     document.write('zero is nothing.'); 
     break; 
    case -1: 
     document.write('low'); 
     break; 
    case -2: 
     document.write('lower'); 
     break; 
    case -3: 
     document.write('lowest I care about'); 
     break; 
    default: // anything lower than -3. 
     document.write('TOO LOW!!!! (unless you cheated and didn\'t use an int)'); 
} 
document.write('<br>done.'); 
+0

Это может обмануть JSLint, но более странно и сложнее читать, чем то, о чем жаловался JSLint. Если вы приняли сознательное решение использовать «switch» с выражениями в случаях, подобных OP, и MooGoo объяснил, тогда вы не будете беспокоиться об этом конкретном предупреждении JSLint. – nnnnnn

+0

@nnnnnn Ну, я бы сказал, что 'switch (true)' полностью антипаттерн, поскольку MooGoo по существу воссоздает 'if ... else if ... else'. Главное в том, что вопрос заставляет меня думать об одном практическом использовании диапазонов в коммутаторах **, если вы находите себя в парадигме «switch», которая по существу требует двух (+?) Значений по умолчанию **. Аккуратно узнать, что вы можете использовать выражение в 'case', верните значение параметра' switch' и принудительно вызовите этот оператор. Но похоже, что вы голосуете за ответы @Daniel & @ FyodorSoikin «*, а не на то, как работает коммутатор», и я действительно не могу это утверждать;) – ruffin

1

Вы также можете попробовать один из моих любимых конструкций:

function reward(amount) { 
    var $reward = $("#reward"); 
    $reward.text(
     (amount >= 7500 && amount < 10000) ? "Play Station 3" : 
     (amount >= 10000 && amount < 15000)? "XBOX 360" : 
     (amount >= 15000) ?      "iMac" : 
               "No reward" 
    ); 
} 
+0

Не могли бы вы проверить, что сумма под номером if вы оценили их в обратном порядке? –

+0

Я предполагаю, что, конечно, это остановит людей с более высокими наградами от их получения быстрее;) –

+2

Вложенных троичных операторов часто опасаются и обескураживают полностью. Поэтому лучше избегать их использования, если они не являются более простыми, очевидными и более легко поддерживаемыми, чем альтернативные конструкции. Я предпочитаю тесты, которые работают в любом порядке. Однако вы решили написать их, простоту и удобство обслуживания козыря здесь. – robert

0

Мои 2 цента:

В идеале переключатель (в принципе) следует оценивать в одном случае ветвь, тем самым достигая производительности O (1) и (кроме случаев падения), операторы case могут быть переупорядочены каким-либо образом без изменения стратегии ветвления компилятора у.

Если выражения используются (при условии, что язык позволяет это сделать), то теоретически он может следовать больше, чем ветвь.

Компилятор (кроме тех, которые могут разумно сказать, что пытается сделать разработчик) не сможет оптимизировать стратегию ветвления статически и идеально, тем самым теряя свою эффективность.

Пример:

var x = 6, factors = []; 

switch(x){ 

    case (x%2 == 0): factors.push(2); 
    break; 

    case (x%3 == 0): factors.push(3); 
    break; 
    .... 
} 

{Ожидать комментарии на плохой код}

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

Единственная деталь, что она может «выглядеть» более чистой для разработчика, но может привести к сбою в случае дополнительных условий.

1

Ну, вы можете иметь выражения в инструкции case, поэтому ваш коммутатор не является синтаксической ошибкой. Но вы должны понимать, что Дело № сравнивается с использованием === (строгое сравнение).Как только вы это понимаете, значение должно точно соответствовать значению выражения в вашем switch(expression), которое вы можете совершать покупки для выражений в js.

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

function xbox(amount) { return amount >= 10000 && amount < 15000 && amount; } 

function reward(amount) { 
    var ps3 = function(amount) { return amount >= 7500 && amount < 10000 && amount; } 

    function imac(amount) { return amount >= 15000 && amount; } 

    var $reward = $("#reward"); 
    switch (amount) { 
    case ps3(amount): 
     $reward.text("Play Station 3"); 
     break; 
    case xbox(amount): 
     $reward.text("XBOX 360"); 
     break; 
    case imac(amount): 
     $reward.text("iMac"); 
     break; 
    default: 
     $reward.text("No reward"); 
     break; 
    } 
} 
reward(8200)// -> Play Station 3 
reward(11000)// -> XBOX 360 
reward(20000)// -> iMac 

Как вы можете видеть, вы можете определение функций как использовать функцию выражения и. Это не имеет значения. Только то, что выражение в аргументе case является выражением для оценки. Это то же самое, что и вы, только вы не вернули значение, равное сумме, а скорее истинное или ложное значение. В моем примере я возвращаю точную сумму, если мое условие истинно, поэтому вызывать сравнение для соответствия.

Вот ваш фиксированный код:

function reward(amount) { 
    var $reward = $("#reward"); 
    switch (amount) { 
     case (amount >= 7500 && amount < 10000 && amount): 
      $reward.text("Play Station 3"); 
      break; 
     case (amount >= 10000 && amount < 15000 && amount): 
      $reward.text("XBOX 360"); 
      break; 
     case (amount >= 15000 && amount): 
      $reward.text("iMac"); 
      break; 
     default: 
      $reward.text("No reward"); 
      break; 
    } 
} 

Вот спецификация: https://tc39.github.io/ecma262/#sec-switch-statement Ссылка на es2016, потому что это проще для поиска, чем старый ES3 PDF с 1999 года Но он всегда работал так, но это малоизвестный факт.

Я, однако, сомневаюсь, что это быстрее, чем if заявлений. Если вы хотите, чтобы ваш запуск работал быстро, то не коснитесь DOM.

Смежные вопросы