JavaScript o (||) spiegazione dell'assegnazione delle variabili


351

Dato questo frammento di JavaScript ...

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f = a || b || c || d || e;

alert(f); // 4

Qualcuno può spiegarmi come si chiama questa tecnica (la mia ipotesi migliore è nel titolo di questa domanda!)? E come / perché funziona esattamente?

La mia comprensione è che alla variabile fverrà assegnato il valore più vicino (da sinistra a destra) della prima variabile che ha un valore che non è né nullo né indefinito, ma non sono riuscito a trovare molto materiale di riferimento su questa tecnica e ho visto che ha usato molto.

Inoltre, questa tecnica è specifica per JavaScript? So che fare qualcosa di simile in PHP porterebbe ad favere un vero valore booleano, piuttosto che il valore di dse stesso.


4
Vecchia questione, ma per quanto riguarda PHP, v'è un costrutto si può usare: $f=$a or $f=$b or $f=$c; // etc. PHP ha sia l' ||operatore che l' oroperatore, che svolgono lo stesso lavoro; tuttavia orviene valutato dopo l' assegnazione mentre ||viene valutato prima. Questo ti dà anche lo stile perlish di$a=getSomething() or die('oops');
Manngo

1
In PHP 5.3 puoi tralasciare la parte centrale dell'operatore ternario basandoti così ... Puoi anche tagliare un po 'più breve in qualcosa del genere: $f = $a ?: $b ?: $c;
Rei

1
A partire da PHP 7 puoi usarlo ??per questo. $a = $b ?? 'default'
Spencer Ruskin,

@SpencerRuskin così $averrà assegnato il valore di $bif $bè true, altro 'default'?
oldboy

Giusto. Guarda la sezione dell'operatore di coalescenza nulla in questa pagina: php.net/manual/en/migration70.new-features.php
Spencer Ruskin

Risposte:


212

Vedere la valutazione del corto circuito per la spiegazione. È un modo comune di implementare questi operatori; non è univoco per JavaScript.


57
Ricorda solo il 'gotcha', ovvero che l'ultimo verrà sempre assegnato anche se sono tutti indefiniti, nulli o falsi. Impostare qualcosa che sai non è falso, nullo o indefinito alla fine della catena è un buon modo per segnalare che non è stato trovato nulla.
Erik Reppen,

Ho visto questa tecnica per anni, ma ciò che mi ha colpito in quel momento, quando volevo usarlo, è che il risultato dell'espressione non è stato booleano. Non puoi farlo più tardi if( true == f ). Se un numero intero è stato memorizzato in f, questo test restituirà sempre false.

9
In realtà, puoi farlo if(true == f), che è lo stesso di if(f): il test passerà. Se vuoi testare anche il tipo di f, usa un confronto rigoroso:, if(true === f)che fallirà davvero.
Alsciende,

5
Sì, la valutazione del corto circuito è comune. Ma la distinzione qui sta nel modo in cui JavaScript restituisce l'ultimo valore che ha bloccato l'esecuzione. La risposta di Anurag fa molto meglio a spiegare questo.
Ben.12

non sono sicuro se questa è la migliore spiegazione per i principianti. Consiglierei: javascript.info/logical-operators
csguy

198

Questo viene fatto per assegnare un valore predefinito , in questo caso il valore di y, se la xvariabile è falsa .

Gli operatori booleani in JavaScript possono restituire un operando e non sempre un risultato booleano come in altre lingue.

L'operatore Logical OR ( ||) restituisce il valore del suo secondo operando, se il primo è errato, altrimenti viene restituito il valore del primo operando.

Per esempio:

"foo" || "bar"; // returns "foo"
false || "bar"; // returns "bar"

Falsy valori sono quelli che costringere a falsequando usato in contesto booleano, e sono 0, null, undefined, una stringa vuota, NaNe naturalmente false.


1
+1 C'è un altro operatore del genere? O è ||esclusivo.
OscarRyz,

9
@Support (@Oscar): l' &&operatore logico ha un comportamento simile, restituisce il valore del primo operando se è di per sé falso e restituisce il valore del secondo operando, solo se il primo è veritiero , ad esempio ("foo" && "bar") == "bar"e(0 && "bar") == 0
CMS

12
Falsy è in effetti il ​​termine tecnico.
ChaosPandion,

8
Quindi abbiamo imparato a conoscere ||, &&, "Falsy" e "Veramente" in questo post. Migliore risposta con regali "nascosti".
Alex

4
@Alex NB: "Verità" (! "Veramente")
Bumpy

183

Javacript utilizza la valutazione di corto circuito per operatori logici ||e &&. Tuttavia, è diverso da altre lingue in quanto restituisce il risultato dell'ultimo valore che ha interrotto l'esecuzione, anziché un valore trueo false.

I seguenti valori sono considerati falsi in JavaScript.

  • falso
  • nullo
  • "" (stringa vuota)
  • 0
  • Nan
  • non definito

Ignorando le regole di precedenza dell'operatore e mantenendo le cose semplici, i seguenti esempi mostrano quale valore ha interrotto la valutazione e, di conseguenza, viene restituito.

false || null || "" || 0 || NaN || "Hello" || undefined // "Hello"

I primi 5 valori fino a NaNsono falsi, quindi vengono tutti valutati da sinistra a destra, fino a quando non incontra il primo valore di verità - il "Hello"che rende vera l'intera espressione, quindi qualsiasi cosa più in alto non verrà valutata e "Hello"verrà restituita come risultato dell'espressione . Allo stesso modo, in questo caso:

1 && [] && {} && true && "World" && null && 2010 // null

I primi 5 valori sono tutti veritieri e vengono valutati fino a quando non soddisfano il primo valore falsy ( null) che rende l'espressione falsa, quindi 2010non viene più valutata e nullviene restituita come risultato dell'espressione.

L'esempio che hai fornito è l'utilizzo di questa proprietà di JavaScript per eseguire un compito. Può essere utilizzato ovunque sia necessario ottenere il primo valore di verità o falsità tra un insieme di valori. Questo codice di seguito assegnerà il valore "Hello"in bquanto semplifica l'assegnazione di un valore predefinito, invece di eseguire controlli if-else.

var a = false;
var b = a || "Hello";

Potresti chiamare l'esempio seguente uno sfruttamento di questa funzionalità e credo che renda il codice più difficile da leggere.

var messages = 0;
var newMessagesText = "You have " + messages + " messages.";
var noNewMessagesText = "Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText);

All'interno messagesdell'avviso, controlliamo se è falso, e se sì, quindi valutiamo e restituiamo noNewMessagesText, altrimenti valutiamo e restituiamo newMessagesText. Dato che in questo esempio è falso, ci fermiamo a noNewMessagesText e avvisiamo "Sorry, you have no new messages.".


36
Questa è la migliore risposta secondo me a causa della seguente spiegazione:However, it's different to other languages in that it returns the result of the last value that halted the execution, instead of a true, or false value.
mastazi

1
@mastazi Sì, dovrebbe essere in grassetto IMHO.
noober,

6
Dovrebbe essere la risposta, mostra i valori scelti rispetto ai casi di test.
Dadan,

D'accordo, questa è la mia risposta preferita in quanto affronta in modo specifico i problemi di assegnazione delle variabili JavaScript. Inoltre, se si sceglie di utilizzare un ternario come una delle variabili successive per verificare l'assegnazione (dopo l'operatore), è necessario avvolgere il ternario tra parentesi affinché la valutazione dell'assegnazione funzioni correttamente.
Joey T,

questa dovrebbe essere la risposta accettata
Alan,

49

Le variabili Javascript non vengono digitate, quindi a f può essere assegnato un valore intero anche se è stato assegnato tramite operatori booleani.

A f viene assegnato il valore più vicino che non equivale a false . Quindi 0, false, null, non definiti, vengono tutti passati sopra:

alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'

13
Non dimenticare ''anche uguale falso in questo caso.
Brigand,

Voto per sottolineare ciò f is assigned the NEAREST valueche è un punto piuttosto importante qui.
Steviejay,

3
"Il più vicino" non è del tutto vero, anche se ha quell'aspetto. L' ||operatore booleano , essendo un operatore booleano, ha due operandi: un lato sinistro e un lato destro. Se il lato sinistro di ||è vero , l'operazione si risolve sul lato sinistro e il lato destro viene ignorato. Se la parte sinistra è falsa , si risolve nella parte destra. Quindi in null || undefined || 4 || 0realtà si risolve a undefined || 4 || 0chi si risolve a 4 || 0chi si risolve 4.
devios1

29

Non c'è magia ad esso. Le espressioni booleane come a || b || c || dsono valutate pigramente. Interpeter cerca il valore di a, è indefinito, quindi è falso, quindi va avanti, poi vede bquale è nullo, il che dà ancora risultati falsi così va avanti, poi vede c- stessa storia. Alla fine vede de dice 'huh, non è null, quindi ho il mio risultato' e lo assegna alla variabile finale.

Questo trucco funzionerà in tutti i linguaggi dinamici che eseguono una valutazione pigra del cortocircuito delle espressioni booleane. Nei linguaggi statici non verrà compilato (digitare errore). Nelle lingue desiderose di valutare le espressioni booleane, restituirà un valore logico (vale a dire vero in questo caso).


6
Nel linguaggio abbastanza statico C # si può usare ?? operatore come: oggetto f = a ?? b ?? c ?? d ?? e;
Herzmeister,

2
herzmeister - grazie! Non lo sapevo ?? l'operatore può essere incatenato in C # e utilizzato in tecniche di valutazione pigre
Marek

3
Come menzionato altrove, quest'ultimo dverrà assegnato indipendentemente dal fatto che fosse nullo / indefinito o meno.
BlackVegetable,

Una leggera correzione: l' ||operatore risolve sempre l'intero operando del lato destro quando il lato sinistro è errato. Essendo un operatore booleano, vede solo due input: il lato sinistro e il lato destro. Il parser non li vede come una serie di termini, quindi in realtà non si ferma quando trova il primo valore di verità a meno che quel valore sia anche l'operando di sinistra di un altro ||.
devios1

8

Questa domanda ha già ricevuto diverse buone risposte.

In sintesi, questa tecnica sfrutta una caratteristica di come viene compilata la lingua. Cioè, JavaScript "cortocircuita" la valutazione degli operatori booleani e restituirà il valore associato al primo valore della variabile non falsa o qualunque cosa contenga l'ultima variabile. Vedi la spiegazione di Anurag di quei valori che verranno valutati come falsi.

L'uso di questa tecnica non è una buona pratica per diversi motivi; però.

  1. Leggibilità del codice: utilizza operatori booleani e se il comportamento di come viene compilato non è compreso, il risultato atteso sarebbe un valore booleano.
  2. Stabilità: utilizza una funzionalità del modo in cui viene compilata la lingua che è incoerente in più lingue e, di conseguenza, è qualcosa che potrebbe essere oggetto di potenziali cambiamenti in futuro.
  3. Caratteristiche documentate: esiste un'alternativa esistente che soddisfa questa esigenza ed è coerente in più lingue. Questo sarebbe l'operatore ternario:

    ()? valore 1: valore 2.

L'uso dell'operatore ternario richiede un po 'più di battitura, ma distingue chiaramente tra l'espressione booleana che viene valutata e il valore assegnato. Inoltre, può essere concatenato, quindi è possibile ricreare i tipi di assegnazioni predefinite eseguite in precedenza.

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f =  ( a ) ? a : 
                ( b ) ? b :
                       ( c ) ? c :
                              ( d ) ? d :
                                      e;

alert(f); // 4

potentially be targeted for change in the future.si, ma non è così per javascript.
Dadan,

Sono venuto qui e ho visto tutte le risposte di cui sopra e pensavo a me stesso che qualcosa non aveva funzionato. Ho appena letto Clean Code di Robert C Martin e questo tipo di incarico viola sicuramente la regola "Non avere effetti collaterali" ... mentre l'autore stesso afferma che il suo libro è solo una delle molte tecniche per generare un buon codice, io era ancora sorpreso che nessun altro si opponesse a questo tipo di incarico. +1
Albert Rothman,

Grazie per la risposta. Penso che più persone debbano considerare gli effetti collaterali quando scrivono codice, ma fino a quando qualcuno non ha trascorso molto tempo a mantenere il codice di altre persone. Spesso non lo considerano.
WSimpson,

1
Pensi davvero che la mostruosità sia più chiara di a || b || c || d || e?
devios1

1
@AlbertRothman Non vedo effetti collaterali. Nulla viene mutato. È semplicemente una scorciatoia per coalescenza nulla, che è una caratteristica abbastanza comune in molte lingue.
devios1,

7

Restituisce l'output del primo vero valore .

Se tutti sono falsi, restituire l'ultimo valore falso.

Esempio:-

  null || undefined || false || 0 || 'apple'  // Return apple

4

Sta impostando la nuova variabile ( z) sul valore di xse è "verità" (diverso da zero, un oggetto / array / funzione valido / qualunque cosa sia) o yaltrimenti. È un modo relativamente comune di fornire un valore predefinito nel caso in cui xnon esista.

Ad esempio, se si dispone di una funzione che accetta un parametro di callback opzionale, è possibile fornire un callback predefinito che non fa nulla:

function doSomething(data, callback) {
    callback = callback || function() {};
    // do stuff with data
    callback(); // callback will always exist
}

1

Significa che se ximpostato, il valore per zsarà x, altrimenti se yimpostato, il suo valore verrà impostato come zvalore di.

è lo stesso di

if(x)
  z = x;
else
  z = y;

È possibile perché gli operatori logici in JavaScript non restituiscono valori booleani ma il valore dell'ultimo elemento necessario per completare l'operazione (in una frase OR sarebbe il primo valore non falso, in una frase AND sarebbe l'ultimo ). Se l'operazione non riesce, falseviene restituita.


5
questo è sbagliato! if (x) {z = x; } else {z = y;} se il primo valore è falso, il secondo valore viene sempre assegnato indipendentemente dal valore effettivo.
evilpie,

Solo che penso che assegni y alla z se x è falso . Questo è il modo in cui funziona per me in FF, ovviamente, che potrebbe dipendere anche dall'implementazione.
tvanfosson,

7
L'ultima parte sulla restituzione di false non è vera (nessun gioco di parole previsto). Se il primo valore è falso, l' ||operatore restituisce semplicemente il secondo valore, indipendentemente dal fatto che sia vero o meno.
Matthew Crumley,

-1. Lo snippet di codice equivalente è accurato, ma il punto importante è che zviene impostato sul valore xse quel valore è vero . Altrimenti viene impostato sul valore di y. Ciò significa che se xè impostato, ad esempio, 0o la stringa vuota "", questo non fa ciò che dici, poiché quei valori sono falsi .
Daniel Cassidy,

1

Si chiama operatore di corto circuito.

La valutazione del corto circuito dice che il secondo argomento viene eseguito o valutato solo se il primo argomento non è sufficiente per determinare il valore dell'espressione. quando il primo argomento della funzione OR (||) viene valutato come vero, il valore complessivo deve essere vero.

Potrebbe anche essere utilizzato per impostare un valore predefinito per l'argomento della funzione

function theSameOldFoo(name){ 
  name = name || 'Bar' ;
  console.log("My best friend's name is " + name);
}
theSameOldFoo();  // My best friend's name is Bar
theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar`

0

Valuterà X e, se X non è null, la stringa vuota o 0 (falso logico), quindi lo assegnerà a z. Se X è null, la stringa vuota o 0 (falso logico), assegnerà y alla z.

var x = '';
var y = 'bob';
var z = x || y;
alert(z);

Emetterà 'bob';


Dovresti chiarire cosa intendi con "vuoto". Le stringhe vuote vengono forzate false, ma le matrici o gli oggetti vuoti vengono forzati true.
Daniel Cassidy,

@Daniel "null, vuoto o 0" - null si applica rispetto a matrici e oggetti. Punto preso, però.
tvanfosson,

0

Secondo il post del blog di Bill Higgins ; il linguaggio logico di assegnazione OR logico Javascript (febbraio 2007), questo comportamento è vero a partire dalla v1.2 (almeno)

Suggerisce anche un altro uso (citato): " leggera normalizzazione delle differenze tra browser "

// determine upon which element a Javascript event (e) occurred
var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
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.