Приоритет оператора с тернарным оператором Javascript


116

Я не могу осмыслить первую часть этого кода (+ =) в сочетании с тернарным оператором.

h.className += h.className ? ' error' : 'error'

Я думаю, что этот код работает следующим образом:

h.className = h.className + h.className ? ' error' : 'error'

Но это неверно, потому что это дает ошибку в моей консоли.

Итак, мой вопрос: как мне правильно интерпретировать этот код?

Ответы:


141
h.className = h.className + (h.className ? ' error' : 'error')

Вы хотите, чтобы оператор работал h.className, лучше уточните это.
Конечно, вреда не должно быть h.className += ' error', но это уже другое дело.

Также обратите внимание, что он +имеет приоритет над тернарным оператором: Приоритет оператора JavaScript.


3
Я думаю, следует отметить, что, хотя вреда не должно быть h.className += ' error', он также оставляет пустое место в начале строки, если она изначально была пуста. Я считаю, что цель тернарной операции - создать чистую строку.
JMTyler

@JMTyler - Это именно то, что я имел в виду - если все сделано только для того, чтобы с самого начала сохранить место, я этого не стоит. (крайний случай включает точные селекторы jQuery или XPath). В любом случае, спасибо.
Коби

@Kobi +1 только за предупреждение о приоритете оператора!
Эд Чапел

129

Подумайте об этом так:

<variable> = <expression> ? <true clause> : <false clause>

Оператор выполняется в основном следующим образом:

  1. Имеет ли <expression>оценить истинно, или же она вычисляться ложно?
  2. Если <expression>оценивается как истина, то значение <true clause>присваивается <variable>, <false clause>игнорируется, и выполняется следующая инструкция.
  3. Если имеет <expression>значение false, то <true clause>игнорируется и <false clause>присваивается значение <variable>.

При использовании тернарного оператора в этом и других языках важно понимать, что любой код, <expression>содержащийся в нем, должен давать логический результат при оценке: либо true, либо false.

В случае вашего примера замените «назначено» в моем объяснении на «добавлено в» или аналогичное для любой сокращенной арифметики, которую вы используете, если таковая имеется.


Обратите внимание, подходит ли идеальный комментарий :) Он пропускает любое объяснение того, почему левые выражения «сгруппированы вместе» первыми (т. Е. Потому, что они +имеют больший приоритет, чем условный / тернарный оператор (на самом деле условный оператор почти всегда является последним) оценивается в любом выражении)
Gone Coding

10

The +=делает то, что вы хотите, но в тернарном операторе справа от него он проверяет, h.classNameявляется ли он ложным, что было бы, если бы оно было undefined. Если это правда (т.е. если имя класса уже указано), тогда ошибка добавляется с пробелом (т.е. добавляется новый класс), в противном случае она добавляется без пробела.

Код можно переписать, как вы предлагаете, но вам нужно указать, что h.classNameон будет использоваться для сравнения истинности, а не для использования его фактического значения в тернарном операторе, поэтому убедитесь, что вы не беспокоитесь о конкатенации значений одновременно с выполнением вашей тернарной операции:

h.className = h.className + (h.className ? ' error' : 'error');

13
ну да, undefinedэто не ложь, с ним просто обращаются так, как будто это было
Дэвид Хедлунд

4

Правая часть =оператора оценивается слева направо. Так,

g.className = h.className + h.className ? ' error' : 'error';`

эквивалентно

h.className = (h.className + h.className) ? ' error' : 'error';

Чтобы быть эквивалентным

h.className += h.className ? ' error' : 'error';

вы должны разделить троичный оператор в скобках

h.className = h.className + (h.className ? ' error' : 'error');

3
if (h.className) {
    h.className = h.className + ' error';
} else {
    h.className = h.className + 'error';
}

должен быть эквивалентом:

h.className += h.className ? ' error' : 'error';

1

Я знаю, что это очень старый вопрос, но я не на 100% доволен ни одним из ответов, поскольку все они кажутся неполными. Итак, мы снова вернемся к первым принципам:

Общая цель пользователя:

Обобщая код: «Я хочу добавить errorимя класса в строку, необязательно с начальным пробелом, если в строке уже есть имена классов».

Самое простое решение

Как указал Коби, 5 лет назад наличие ведущего пробела в именах классов не вызовет никаких проблем ни с одним из известных браузеров, поэтому кратчайшим правильным решением было бы на самом деле:

h.className += ' error';

Это должно было быть фактическим ответом на настоящую проблему .


Как бы то ни было, задаваемые вопросы были ...

1) Почему это сработало?

h.className += h.className ? ' error' : 'error'

Условный / тройная оператор работает как если утверждение, что присваивает результат его trueили falseпутей к переменной.

Итак, этот код работал, потому что он оценивается просто как:

if (h.className IS NOT null AND IS NOT undefined AND IS NOT '') 
    h.className += ' error'
else
    h.className += 'error'

2) а почему это сломалось?

h.className = h.className + h.className ? ' error' : 'error'

Вопрос гласит: «Это вызывает ошибку [n] в моей консоли», что может ввести вас в заблуждение, заставив думать, что код не работает . Фактически, следующий код выполняется без ошибок , но он просто возвращает «error», если строка не была пустой, и «error», если строка была пустой и поэтому не соответствовала требованиям .

Этот код всегда приводит к строке, которая содержит только этот псевдокод ' error'или 'error'потому, что он оценивает его:

if ((h.className + h.className) IS NOT null AND IS NOT undefined AND IS NOT '')
    h.className = ' error'
else
    h.className = 'error'

Причина этого в том, что оператор сложения ( +к простому народу) имеет более высокий «приоритет» (6), чем условный / тернарный оператор (15). Я знаю, что числа идут наоборот

Приоритет просто означает, что каждый тип оператора на языке оценивается в определенном заранее определенном порядке (а не только слева направо).

Ссылка: Приоритет операторов Javascript

Как изменить порядок оценки:

Теперь мы знаем, почему он не работает, и вам нужно знать, как заставить его работать.

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

Инструмент в нашем наборе инструментов, который может изменить порядок оценки, - это оператор группировки (он же скобки). Это достигается за счет того, что выражения в квадратных скобках оцениваются перед операциями вне скобок. Это все, что они делают, но этого достаточно.

Скобки работают просто потому, что они (операторы группировки) имеют более высокий приоритет, чем все другие операторы («теперь уровень 0»).

Просто добавляя скобки, вы изменяете порядок оценки, чтобы сначала выполнялась условная проверка, перед простой конкатенацией строк:

h.className = h.className + (h.className ? ' error' : 'error')

Теперь я оставлю этот ответ незаметной ржавчине среди других :)


1

Я бы хотел подобрать объяснение Уэйна:

<variable> = <expression> ? <true clause> : <false clause>

Рассмотрим оба случая:

case 1:
h.className += h.className ? 'true' : 'false'     
  • оператор присваивания работает нормально, и значение добавляется
  • при первом запуске o / p: false
  • 2-й раз. o / p: falsetrue - значения продолжают добавляться

case2: h.className = h.className + h.className? 'истина': 'ложь'

  • результат не такой, как в случае 1
  • при первом запуске o / p: false
  • 2-й раз. o / p: false - значения не добавляются

explanation

В приведенном выше коде случай 1 работает нормально

тогда как case2:

h.className = h.className + h.className ? 'true' : 'false'
is executed as 
 h.className = (h.className + h.className) ? 'true' : 'false'

h.className + h.className=> рассматривается как выражение для тернарного оператора, поскольку тернарный оператор имеет более высокий приоритет. так что всегда результат тернарного выражения просто присваивается

Вам необходимо определить приоритет, используя скобки

Вам необходимо определить порядок оценки с помощью скобок, чтобы случай 2 работал как случай 1.

h.className = h.className + (h.className ? ' error' : 'error') 

1
Терминология здесь не совсем верная. Приоритет присущ языку, вы не определяете его . Вместо этого вы определяете порядок оценки , вводя скобки (которые имеют более высокий приоритет, чем все другие операторы).
Gone Coding

@TrueBlueAussie Я принимаю это. я благодарен за ваше пристальное внимание к чтению +1
Angelin Nadar
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.