Пріоритет оператора перед оператором Javascript Ternary


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 лише для попередження про пріоритет оператора!
Ed Chapel

129

Подумайте про це так:

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

Спосіб виконання оператора полягає в наступному:

  1. Чи <expression>оцінюється до істинного, чи оцінюється до хибного?
  2. Якщо <expression>оцінюється як true, тоді значення <true clause>присвоюється <variable>, <false clause>ігнорується, і наступне твердження виконується.
  3. Якщо <expression>оцінюється як false, то <true clause>він ігнорується і <false clause>присвоюється значення <variable>.

Важливе, що потрібно зрозуміти разом із потрійним оператором на цій та інших мовах, - це те, що будь-який код <expression>повинен створювати логічний результат при оцінці: істинний, або хибний.

У випадку вашого прикладу замініть на "призначений" у моєму поясненні на "додано до" або подібне для тієї чи іншої стенографічної арифметики, яку ви використовуєте, якщо така є.


Зауважте, чи підходить ідеальний коментар :) Пропускає будь-яке пояснення того, чому ліві вирази спочатку "згрупуються" (тобто тому, що +мають більший пріоритет, ніж умовний / потрійний оператор (насправді умовний оператор майже завжди є останнім) оцінюється в будь-якому виразі).
Пройшло кодування

10

+=Робить те , що ви хочете, але в потрійному заяві на праву руку від нього, він перевіряє, h.classNameє falsey, які було б , якщо він був визначений. Якщо це truthy (тобто якщо ім'я класу вже вказано), помилка додається з пробілом (тобто додаванням нового класу), інакше додається без пробілу.

Код можна переписати так, як ви пропонуєте, але вам потрібно вказати, що 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'

Умовний / потрійний оператор працює як оператор if, який присвоює результат своєї змінної 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'тому, що він оцінює цей псевдо-код:

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

Я хотів би вибрати пояснення Wayne:

<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? 'true': 'false'

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

explanation

У наведеному вище коді випадок 1 працює добре

тоді як випадок2:

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

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

Визначити пріоритет потрібно за допомогою дужок

Вам потрібно визначити порядок оцінювання, який слід розглядати за допомогою дужок, щоб випадок 2 працював як перший випадок

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

1
Термінологія тут не зовсім правильна. Прецедент притаманний мові, ви її не визначаєте . Ви натомість визначаєте порядок оцінювання , вводячи дужки (які мають вищий пріоритет, ніж усі інші оператори).
Пройшов кодування

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