Альтернатива вложенному тернарному оператору в JS
Я лично люблю тернарные операторы, и по моему скромному мнению, они делают сложные выражения очень легко усваивается. Возьмите вот это:--2-->
word = (res.distance === 0) ? 'a'
: (res.distance === 1 && res.difference > 3) ? 'b'
: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
: 'd';
однако в правилах ESLINT нашего проекта вложенные тернарные операторы запрещены, поэтому я должен избавиться от вышеуказанного.
Я пытаюсь найти альтернативы такому подходу. Я действительно не хочу превращать его в огромное заявление if / else, но не знаю, есть ли другие варианты.
8 ответов
ваши альтернативы здесь в основном:
- это
if
/else
вы не хотите делать - A
switch
в сочетании сif
/else
я попытался придумать разумный вариант карты поиска, но он стал необоснованным довольно быстро.
я бы пошел на #1, это:
if (res.distance == 0) {
word = 'a';
} else if (res.distance == 1 && res.difference > 3) {
word = 'b';
} else if (res.distance == 2 && res.difference > 5 && String(res.key).length > 5) {
word = 'c';
} else {
word = 'd';
}
если все фигурные скобки и вертикальный размер беспокоят вас, без них это почти так же лаконично, как условное версия оператора:
if (res.distance == 0) word = 'a';
else if (res.distance == 1 && res.difference > 3) word = 'b';
else if (res.distance == 2 && res.difference > 5 && String(res.key).length > 5) word = 'c';
else word = 'd';
(я не выступаю за это, я никогда не выступаю за то, чтобы оставить скобки или поставить заявление после if
на той же линии, но у других разные перспективы стиля.)
#2, на мой взгляд, более неуклюжий, но это, вероятно, больше комментарий стиля, чем что-либо еще:
word = 'd';
switch (res.distance) {
case 0:
word = 'a';
break;
case 1:
if (res.difference > 3) {
word = 'b';
}
break;
case 2:
if (res.difference > 5 && String(res.key).length > 5) {
word = 'c';
}
break;
}
и, наконец, и я не защищаю это, вы можете воспользоваться тем, что JavaScript switch
необычно в B-семейство языков синтаксиса:case
заявления может быть выражения, и сопоставляются со значением коммутатора в порядке исходного кода:
switch (true) {
case res.distance == 0:
word = 'a';
break;
case res.distance == 1 && res.difference > 3:
word = 'b';
break;
case res.distance == 2 && res.difference > 5 && String(res.key).length > 5:
word = 'c';
break;
default:
word = 'd';
break;
}
насколько это уродливо? :-)
на мой вкус, тщательно структурированная вложенная тройка бьет все эти грязные ifs и переключатели:
const isFoo = res.distance === 0;
const isBar = res.distance === 1 && res.difference > 3;
const isBaz = res.distance === 2 && res.difference > 5 && String(res.key).length > 5;
const word =
isFoo ? 'a' :
isBar ? 'b' :
isBaz ? 'c' :
'd' ;
если все ваши условия truthy оцениваются в значения truthy (поэтому значение между вопросительным знаком и точкой с запятой оценивается как true, если принуждается к boolean...) вы можете сделать ваши тернарные выражения return false
как ложное выражение. Затем вы можете связать их побитовым или (||
) оператор для проверки следующего условия, до последнего, где вы возвращаете значение по умолчанию.
в приведенном ниже примере массив "condsXXX" представляет собой результат оценки условия. "conds3rd" имитирует 3-е условие является "истиной" и "condsNone" имитирует не условие. В коде реальной жизни у вас были бы условия "inlined" в выражении назначения:
var conds3rd = [false, false, true];
var condsNone = [false, false, false];
var val3rd = (conds3rd[0] ? 1 : false) ||
(conds3rd[1] ? 2 : false) ||
(conds3rd[2] ? 3 : 4);
var valNone = (condsNone[0] ? 1 : false) ||
(condsNone[1] ? 2 : false) ||
(condsNone[2] ? 3 : 4);
alert(val3rd);
alert(valNone);
ваш пример может закончиться, как показано ниже:
word = ((res.distance === 0) ? 'a' : false) ||
((res.distance === 1 && res.difference > 3) ? 'b' : false) ||
((res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : 'd';
в качестве примечания, я не чувствую, что это хороший код, но он довольно близок к использованию чистого троичного оператора, как вы стремитесь сделать...
word = (res.distance === 0) ? 'a'
: (res.distance === 1 && res.difference > 3) ? 'b'
: (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c'
: 'd';
Это старый вопрос, но вот как я бы это сделал... Я бы начал с случая по умолчанию, а затем изменил переменную или передал ее без изменений по желанию.
var word = 'd';
word = (res.distance === 0) ? 'a' : word;
word = (res.distance === 1 && res.difference > 3) ? 'b' : word
word = (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) ? 'c' : word;
вы могли бы написать сразу же вызывается функция-выражение чтобы сделать его немного более читаемым:
const word = (() => {
if (res.distance === 0) return 'a';
if (res.distance === 1 && res.difference > 3) return 'b';
if (res.distance === 2 && res.difference > 5 && String(res.key).length > 5) return 'c';
return 'd';
})();
Если вы хотите использовать const с вложенным тернарным выражением, вы можете заменить тернарное выражение выражением функции.
const res = { distance: 1, difference: 5 };
const branch = (condition, ifTrue, ifFalse) => condition?ifTrue:ifFalse;
const word = branch(
res.distance === 0, // if
'a', // then
branch( // else
res.distance === 1 && res.difference > 3, // if
'b', // then
branch( // else
res.distance === 2 && res.difference > 5, // if
'c', // then
'd' // else
)
)
);
console.log(word);
или используя именованные параметры через деконструкцию...
const branch2 = function(branch) {
return branch.if ? branch.then : branch.else;
}
const fizzbuzz = function(num) {
return branch2({
if: num % 3 === 0 && num % 5 === 0,
then: 'fizzbuzz',
else: branch2({
if: num % 3 === 0,
then: 'fizz',
else: branch2({
if: num % 5 === 0,
then: 'buzz',
else: num
})
})
});
}
console.log(
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].map(
cv => fizzbuzz(cv)
)
);
... edit: возможно, будет яснее моделировать его после python, если выражение таково:
const res = { distance: 1, difference: 5 };
const maybe = def => ({
if: expr => {
if (expr) {
return { else: () => def };
} else {
return { else: els => els };
}
}
});
const word = maybe('a').if(res.distance === 0).else(
maybe('b').if(res.distance === 1 && res.difference > 3).else(
maybe('c').if(res.distance === 2 && res.difference > 5).else('d')
)
);
console.log(word);
я столкнулся с этим слишком недавно, и поиск google привел меня сюда, и я хочу поделиться тем, что я недавно обнаружил в отношении этого:
a && b || c
это почти то же самое как
a ? b : c
пока b
- истина. Если b
это не правда, вы можете обойти это, используя
!a && c || b
если c
- истина.
первое выражение оценивается как (a && b) || c
as &&
имеет больший приоритет, чем ||
.
если a
- истина тогда a && b
возвращает b
Если b
истинно, поэтому выражение становится b || c
который оценивает в b
если это правда, так же, как a ? b : c
если бы a
это правда, и если a
не является правдивым, тогда выражение будет оцениваться как c
по мере необходимости.
чередуя &&
и ||
хитрость и ?
и ||
в слоях трюков оператора правило no-nested-ternary eslint, которое довольно аккуратно (хотя я бы не рекомендовал делать это, если нет другого выхода).
быстрая демонстрация:
true ? false ? true : true ? false : true ? true ? true : false : true : true
// which is interpreted as
true ? (false ? true : (true ? false : (true ? (true ? true : false) : true))) : true
// now with the trick in alternate levels
true ? (false && true || (true ? false : (true && (true ? true : false) || true))) : true
// all of these evaluate to false btw
я на самом деле немного обманул, выбрав пример, где b
всегда правдиво, но если вы просто устанавливаете строки, то это должно работать нормально, как даже '0'
по иронии судьбы является истина.
я использовал оператор switch(true) для этих случаев. На мой взгляд, этот синтаксис кажется немного более элегантным, чем вложенные операторы if/else
switch (true) {
case condition === true :
//do it
break;
case otherCondition === true && soOn < 100 :
// do that
break;
}