Альтернатива вложенному тернарному оператору в JS
Я лично люблю тройных операторов, и, по моему скромному мнению, они делают сложные выражения очень легко усваиваемыми. Возьмите это:
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, но не знаю, есть ли другие варианты.
Ответы
Ответ 1
Ваши альтернативы здесь в основном:
- Это
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 -syntax language family: Операторы 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;
}
Как уродливо это?: -)
Ответ 2
Если все ваши истинные условия оцениваются с помощью правдивых значений (поэтому значение между вопросительным знаком и точкой с запятой оценивается как true, если принудительно булевать...), вы можете заставить ваши тернарные выражения возвращать false
в качестве фальшивого выражения. Затем вы можете связать их с побитовым или (||
) оператором, чтобы проверить следующее условие, до последнего, где вы вернете значение по умолчанию.
В приведенном ниже примере массив "condsXXX" представляет результат оценки условий. "conds3rd" имитирует третье условие, это правда, и "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);
Ответ 3
На мой взгляд, тщательно структурированная вложенная тройка бьет все эти беспорядочные 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' ;
Ответ 4
Если вы хотите использовать 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);
// or using named parameter via destructuring
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)
)
);
Ответ 5
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;
Ответ 6
Я столкнулся с этим совсем недавно, и поисковик Google привел меня сюда, и я хочу поделиться тем, что я недавно узнал об этом:
a && b || c
почти то же самое, что и
a ? b : c
пока b
правдиво. Если b
не является правдивым, вы можете обойти его, используя
!a && c || b
если c
является правдой.
Первое выражение оценивается как (a && b) || c
, поскольку &&
имеет больший приоритет, чем ||
.
Если a
является правдивым, тогда a && b
будет оценивать до b
, если b
является правдивым, поэтому выражение становится b || c
, которое оценивается как b
, если оно правдиво, так же, как a ? b : c
если a
является правдивым, а если a
не является правдивым, тогда выражение будет оценивать до c
по мере необходимости.
Чередование трюков &&
и ||
и ?
и ||
в слоях инструкции трюки - правило не-вложенных тройных правил 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'
иронически правдоподобно.
Ответ 7
Я использовал оператор switch (true) для этих случаев. По-моему, этот синтаксис выглядит немного более элегантным, чем вложенные операторы if/else
switch (true) {
case condition === true :
//do it
break;
case otherCondition === true && soOn < 100 :
// do that
break;
}
Ответ 8
Вы можете написать сразу вызываемое выражение функции, чтобы сделать его более читаемым:
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';
})();
Ссылка на ответ