Precedenza operatore con operatore ternario Javascript


116

Non riesco a capire la prima parte di questo codice (+ =) in combinazione con l'operatore ternario.

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

Il modo in cui penso che questo codice funzioni è il seguente:

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

Ma questo non è corretto perché dà un errore nella mia console.

Quindi la mia domanda è: come devo interpretare correttamente questo codice?

Risposte:


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

Vuoi che l'operatore lavori per h.className, meglio essere specifico al riguardo.
Ovviamente non dovrebbe derivare alcun danno h.className += ' error', ma questa è un'altra questione.

Inoltre, nota che +ha la precedenza sull'operatore ternario: JavaScript Operator Precedence


3
Penso che dovrebbe essere notato che, sebbene nessun danno possa derivare da h.className += ' error', lascia anche uno spazio vuoto all'inizio della stringa se inizialmente era vuoto. Credo che lo scopo dell'operazione ternaria sia produrre una corda dall'aspetto pulito.
JMTyler

@ JMTyler - Questo è esattamente quello che stavo indicando - Se è tutto fatto solo per mantenere uno spazio dall'inizio, non ne vale la pena. (il caso limite include i selettori jQuery o XPath esatti). Comunque grazie.
Kobi

@Kobi +1 solo per l'avviso di precedenza dell'operatore!
Ed Chapel

129

Pensare in questo modo:

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

Il modo in cui l'istruzione viene eseguita è fondamentalmente il seguente:

  1. Non <expression>valutare al vero, o lo fa restituiscono falso?
  2. Se <expression>restituisce true, il valore di <true clause>viene assegnato a <variable>, <false clause>viene ignorato e viene eseguita l'istruzione successiva.
  3. Se <expression>restituisce false, <true clause>viene ignorato e il valore di <false clause>viene assegnato a <variable>.

La cosa importante da realizzare con l'operatore ternario in questo e in altri linguaggi è che qualunque codice si trovi <expression>dovrebbe produrre un risultato booleano quando valutato: vero o falso.

Nel caso del tuo esempio, sostituisci "assegnato a" nella mia spiegazione con "aggiunto a", o simile per qualsiasi aritmetica abbreviata che stai usando, se esiste.


Nota bene se il commento perfetto è appropriato :) Salta ogni spiegazione del motivo per cui le espressioni di sinistra "raggruppate insieme" per prime (cioè perché +ha una precedenza maggiore dell'operatore condizionale / ternario (infatti l'operatore condizionale è quasi sempre l'ultimo valutato in qualsiasi espressione)
Gone Coding

10

Il +=fa quello che vuoi, ma h.classNamenell'affermazione ternaria alla destra di esso, controlla se è falso, che sarebbe se fosse indefinito. Se è vero (cioè se il nome di una classe è già specificato), allora l'errore viene aggiunto con uno spazio (cioè aggiungendo una nuova classe), altrimenti viene aggiunto senza lo spazio.

Il codice potrebbe essere riscritto come suggerisci, ma devi specificare che h.classNamedeve essere utilizzato per il confronto di veridicità, piuttosto che per utilizzare il suo valore effettivo, nell'operatore ternario, quindi assicurati di non preoccuparti della concatenazione dei valori contemporaneamente all'operazione ternaria:

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

13
beh sì, undefinednon è falso , è trattato come se fosse
David Hedlund

4

Il lato destro =dell'operatore viene valutato da sinistra a destra. Così,

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

è equivalente a

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

Essere equivalente a

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

devi separare l'affermazione ternaria tra parentesi

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

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

dovrebbe essere equivalente a:

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

1

So che questa è una domanda molto vecchia, ma non sono soddisfatto al 100% di nessuna delle risposte poiché sembrano tutte incomplete. Quindi eccoci di nuovo dai primi presidi:

L'obiettivo generale dell'utente:

Riassumendo il codice: "Desidero aggiungere un errornome di classe a una stringa, opzionalmente con uno spazio iniziale se nella stringa sono già presenti nomi di classe."

La soluzione più semplice

Come ha sottolineato Kobi, 5 anni fa, avere uno spazio principale nei nomi delle classi non causerà alcun problema con nessun browser noto, quindi la soluzione corretta più breve sarebbe in realtà:

h.className += ' error';

Questa avrebbe dovuto essere la risposta effettiva al problema reale .


Comunque sia, le domande poste erano ...

1) Perché ha funzionato?

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

L'operatore condizionale / ternario funziona come un'istruzione if, che assegna il risultato dei suoi percorsi trueo falsea una variabile.

Quindi quel codice ha funzionato perché viene valutato semplicemente come:

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

2) e perché questa rottura?

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

La domanda afferma "che dà un [n] errore nella mia console", il che potrebbe indurti a pensare che il codice non funzioni . Infatti il ​​codice seguente viene eseguito, senza errori , ma restituisce semplicemente "errore" se la stringa non era vuota e "errore" se la stringa era vuota e quindi non soddisfaceva i requisiti .

Quel codice risulta sempre in una stringa che contiene solo ' error'o 'error'perché restituisce questo pseudo codice:

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

La ragione di ciò è che l'operatore di addizione ( +alla gente comune) ha una "precedenza" (6) maggiore dell'operatore condizionale / ternario (15). So che i numeri appaiono al contrario

Precedenza significa semplicemente che ogni tipo di operatore in una lingua viene valutato in un particolare ordine predefinito (e non solo da sinistra a destra).

Riferimento: precedenza degli operatori Javascript

Come modificare l'ordine di valutazione:

Ora sappiamo perché fallisce, devi sapere come farlo funzionare.

Alcune altre risposte parlano di cambiare la precedenza , ma non puoi . La precedenza è cablata nella lingua. Questo è solo un insieme fisso di regole ... Tuttavia, puoi cambiare l' ordine di valutazione ...

Lo strumento nella nostra casella degli strumenti che può cambiare l'ordine di valutazione è l'operatore di raggruppamento (noto anche come parentesi). Lo fa assicurandosi che le espressioni tra parentesi siano valutate prima delle operazioni al di fuori delle parentesi. È tutto quello che fanno, ma è abbastanza.

Le parentesi funzionano semplicemente perché (operatori di raggruppamento) hanno una precedenza maggiore rispetto a tutti gli altri operatori ("ora c'è un livello 0").

Aggiungendo semplicemente parentesi si modifica l'ordine di valutazione per garantire che il test condizionale venga eseguito prima, prima della semplice concatenazione di stringhe:

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

Ora lascerò questa risposta alla ruggine invisibile tra le altre :)


1

Vorrei scegliere una spiegazione di Wayne:

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

Consideriamo entrambi i casi:

case 1:
h.className += h.className ? 'true' : 'false'     
  • l'operatore di assegnazione funziona bene e il valore viene aggiunto
  • quando viene eseguito per la prima volta, o / p: false
  • 2a volta. o / p: falsetrue - i valori continuano ad essere aggiunti

case2: h.className = h.className + h.className? 'vero falso'

  • il risultato non è lo stesso del caso 1
  • quando viene eseguito per la prima volta, o / p: false
  • 2a volta. o / p: false - i valori non continuano ad essere aggiunti

explanation

Nel codice sopra, il caso 1 funziona bene

mentre case2:

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

h.className + h.className=> considerato come espressione per operatore ternario in quanto operatore ternario ha la precedenza maggiore. quindi, il risultato dell'espressione ternaria è sempre assegnato

È necessario definire la precedenza utilizzando le parentesi

È necessario definire l'ordine di valutazione da considerare con l'aiuto delle parentesi affinché il caso 2 funzioni come il caso 1

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

1
La terminologia qui non è del tutto corretta. La precedenza è insita nella lingua, non la definisci . Stai invece definendo l' ordine di valutazione introducendo parentesi (che hanno la precedenza maggiore rispetto a tutti gli altri operatori).
Gone Coding

@TrueBlueAussie Lo accetto. Apprezzo per la tua intenzione di leggere +1
Angelin Nadar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.