Cosa significa il costrutto x = x || intendi?


250

Sto eseguendo il debug di alcuni JavaScript e non riesco a spiegare cosa ||fa?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

Qualcuno può darmi un suggerimento, perché questo ragazzo sta usando var title = title || 'ERROR'? A volte lo vedo anche senza una vardichiarazione.


44
Le persone hanno già risposto a questo ... ma sii estremamente consapevole del fatto che il secondo valore viene scelto se il primo valore è falsy, non SOLO undefined. Il numero di volte che ho visto doWeDoIt = doWeDoIt || trueè abbastanza per farmi piangere. (cioè doWeDoItora non lo sarà mai false)
Matt


4
Per coloro che hanno esperienza con C #, l'operatore double pipe equivale all'operatore null-coalesce ??. Javascript valuta oggetti non nulli come true (o meglio evalualte oggetti null su falso)
usr-local-ΕΨΗΕΛΩΝ

3
Non sentirti male - JS è l'unico linguaggio sciocco che consente questo orribile codice .... che e insegnando che è giusto annidare ogni funzione in righe di codice e gettarle via rendendole usa e getta e inutilizzabili una seconda volta. :) Sono 30 anni in programmazione e mi sono trattenuto dal toccare JS fino a non molto tempo fa me stesso e sento il tuo dolore tutto ciò che posso dire è, tenere a portata di mano un foglio di "non ha senso, è solo in JS" è l'unico modo in cui io ' ci sono passato! :)
Collin Chaffin,

1
Ti preghiamo di considerare di cambiare la risposta accettata alla mia risposta .
Michał Perłakowski il

Risposte:


210

Significa che l' titleargomento è facoltativo. Pertanto, se si chiama il metodo senza argomenti, verrà utilizzato un valore predefinito di "Error".

È una scorciatoia per scrivere:

if (!title) {
  title = "Error";
}

Questo tipo di trucco abbreviato con espressioni booleane è comune anche in Perl. Con l'espressione:

a OR b

valuta truese uno dei due ao lo bè true. Quindi, se aè vero, non è necessario controllare baffatto. Questo si chiama valutazione booleana di corto circuito, quindi:

var title = title || "Error";

fondamentalmente controlla se titlevaluta false. Se lo fa, "ritorna" "Error", altrimenti ritorna title.


3
Mi dispiace essere schizzinoso, ma l'argomento non è facoltativo, l'argomento è verificato
themightybun

4
Questa NON è la risposta e sono d'accordo con l'ultimo commento, non è nemmeno facoltativo. Nessuna parte di questa risposta è corretta nemmeno il riferimento Perl poiché l'istruzione Perl rende effettivamente SENSE ed è valutata in un modo completamente diverso. Il JS è eval in un metodo logico booleano molto più "convertito" che anch'io trovo molto più confuso da leggere / scrivere. La risposta di seguito intitolata "Cos'è l'operatore double pipe" è in realtà una risposta corretta.
Collin Chaffin,

198

Cos'è l'operatore double pipe ( ||)?

L'operatore double pipe ( ||) è l' operatore logicoOR . Nella maggior parte delle lingue funziona nel modo seguente:

  • Se il primo valore è false, controlla il secondo valore. Se lo è true, ritorna truee se lo è false, ritorna false.
  • Se il primo valore è true, restituisce sempre true, qualunque sia il secondo valore.

Quindi sostanzialmente funziona come questa funzione:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

Se ancora non capisci, guarda questa tabella:

      | true   false  
------+---------------
true  | true   true   
false | true   false  

In altre parole, è falso solo quando entrambi i valori sono falsi.

In cosa differisce in JavaScript?

JavaScript è un po 'diverso, perché è un linguaggio vagamente digitato . In questo caso significa che è possibile utilizzare l' ||operatore con valori non booleani. Sebbene non abbia senso, è possibile utilizzare questo operatore con ad esempio una funzione e un oggetto:

(function(){}) || {}

Cosa succede lì?

Se i valori non sono booleani, JavaScript rende la conversione implicita in booleano . Ciò significa che se il valore è falsey (ad esempio 0, "", null, undefined(vedi anche Tutti i valori Falsey in JavaScript )), viene trattata come false; altrimenti viene trattato come true.

Quindi l'esempio sopra dovrebbe dare true, perché la funzione vuota è vera. Beh, non lo fa. Restituisce la funzione vuota. Questo perché l' ||operatore JavaScript non funziona come ho scritto all'inizio. Funziona nel modo seguente:

  • Se il primo valore è false , restituisce il secondo valore .
  • Se il primo valore è vero , restituisce il primo valore .

Sorpreso? In realtà, è "compatibile" con l' ||operatore tradizionale . Potrebbe essere scritto come la seguente funzione:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

Se passi un valore di verità come x, restituisce x, cioè un valore di verità. Quindi, se lo usi in seguito nella ifclausola:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

hai capito "Either x or y is truthy.".

Se xfosse falso, lo eitherXorYsarebbe y. In questo caso otterresti il "Either x or y is truthy."se yfosse sincero; altrimenti otterresti "Neither x nor y is truthy".

La vera domanda

Ora, quando sai come ||funziona l'operatore, probabilmente puoi capire da solo cosa x = x || ysignifica. Se xè vero, xè assegnato a x, quindi in realtà non accade nulla; altrimenti yè assegnato a x. È comunemente usato per definire i parametri predefiniti nelle funzioni. Tuttavia, è spesso considerata una cattiva pratica di programmazione , perché impedisce di passare un valore di falso (che non è necessariamente undefinedo null) come parametro. Prendi in considerazione il seguente esempio:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Sembra valido a prima vista. Tuttavia, cosa accadrebbe se passassi falsecome flagAparametro (dato che è booleano, cioè può essere trueo false)? Lo sarebbe true. In questo esempio, non è possibile impostare flagAsu false.

Sarebbe meglio verificare esplicitamente se flagAè undefinedcosì:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Anche se è più lungo, funziona sempre ed è più facile da capire.


È inoltre possibile utilizzare la sintassi ES6 per i parametri delle funzioni predefinite , ma si noti che non funziona nei browser più vecchi (come IE). Se vuoi supportare questi browser, dovresti trascrivere il tuo codice con Babel .

Vedi anche Operatori logici su MDN .


13
+1 - di gran lunga la risposta più corretta e completa. E, per quelli con questa domanda (alcuni di noi programmatori veterani nuovi di JS inclusi) dovrebbero certamente concentrarsi maggiormente su tutta questa risposta su questa linea: "Anche se non ha senso" perché questo "loosley digitato" semplicemente non avrà mai senso a quelli di noi che sono cresciuti senza di essa. Per noi, un operatore booleano è proprio questo e SOLO quello ...... e chiunque abbia mai pensato che sarebbe una buona idea fermarsi e pensare attraverso una stravagante conversione di valori non booleani in booleani durante la lettura / scrittura del codice , ho dimenticato di prendere le loro medicine quel giorno! :)
Collin Chaffin,

2
+1, in breve: title = title || 'Error'significaif (title) { title = title; } else { title = 'Error'; }
Andre Elrico,

In realtà non sono d'accordo con la linea "sebbene non abbia senso". Capisco che la riga non verrà compilata in C, ad esempio, ma è ben chiaro se vieni da Ruby per esempio, o anche Groovy. In Ruby potresti esprimerlo ancora più breve, come title ||= 'Error'.
Elliot Nelson,

28

Se il titolo non è impostato, utilizzare 'ERRORE' come valore predefinito.

Più generico:

var foobar = foo || default;

Legge: imposta foobar su fooo default. Potresti anche incatenarlo molte volte:

var foobar = foo || bar || something || 42;

1
L'ho trovato confuso perché le variabili hanno lo stesso nome. Molto più facile quando non lo fanno.
Norbert Norbertson,

14

Spiegandolo un po 'di più ...

L' ||operatore è l' oroperatore logico . Il risultato è vero se la prima parte è vera ed è vera se la seconda parte è vera ed è vera se entrambe le parti sono vere. Per chiarezza, eccolo in una tabella:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

Ora noti qualcosa qui? Se Xè vero, il risultato è sempre vero. Quindi, se sappiamo che Xè vero, non dobbiamo controllare Yaffatto. Molti linguaggi implementano quindi i valutatori di "corto circuito" per la logica or(e la logica andproveniente dall'altra direzione). Controllano il primo elemento e se è vero non si preoccupano affatto di controllare il secondo. Il risultato (in termini logici) è lo stesso, ma in termini di esecuzione c'è potenzialmente una differenza enorme se il secondo elemento è costoso da calcolare.

Cosa c'entra questo con il tuo esempio?

var title   = title || 'Error';

Diamo un'occhiata a quello. L' titleelemento viene passato alla tua funzione. In JavaScript se non si passa un parametro, il valore predefinito è un valore null. Anche in JavaScript se la tua variabile è un valore nullo, viene considerata falsa dagli operatori logici. Quindi se questa funzione viene chiamata con un titolo dato, è un valore non falso e quindi assegnato alla variabile locale. Se, tuttavia, non viene assegnato un valore, è un valore null e quindi falso. L' oroperatore logico quindi valuta la seconda espressione e restituisce invece "Errore". Quindi ora alla variabile locale viene assegnato il valore "Errore".

Questo funziona a causa dell'implementazione delle espressioni logiche in JavaScript. Non restituisce un valore booleano corretto ( trueo false), ma restituisce invece il valore che è stato dato in alcune regole su ciò che è considerato equivalente truee ciò che è considerato equivalente false. Cerca il tuo riferimento JavaScript per scoprire ciò che JavaScript considera vero o falso in contesti booleani.


8

Double pipe significa "OR" logico. Questo non è proprio il caso del "parametro non impostato", poiché rigorosamente nel javascript se si dispone di codice come questo:

function foo(par) {
}

Quindi chiama

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

non sono equivalenti.

La doppia pipe (||) lancerà il primo argomento in booleano e se il booleano risultante è vero - esegui l'assegnazione altrimenti assegnerà la parte giusta.

Questo è importante se si controlla il parametro non impostato.

Diciamo che abbiamo una funzione setSalary che ha un parametro opzionale. Se l'utente non fornisce il parametro, utilizzare il valore predefinito 10.

se esegui il controllo in questo modo:

function setSalary(dollars) {
    salary = dollars || 10
}

Ciò darà risultati imprevisti su chiamate simili

setSalary(0) 

Continuerà a impostare il 10 seguendo il flusso sopra descritto.


8

Fondamentalmente controlla se il valore prima del || restituisce vero, in caso affermativo, prende questo valore, in caso contrario, prende il valore dopo il ||.

Valori per i quali assumerà il valore dopo il || (per quanto mi ricordo):

  • non definito
  • falso
  • 0
  • '' (Stringa Null o Null)

1
falso || null || non definito || 0 || '' || 'hai dimenticato null'
Dziamid

7

Sebbene la risposta di Cletus sia corretta, ritengo che si debbano aggiungere ulteriori dettagli per quanto riguarda "valuta falso" in JavaScript.

var title = title || 'Error';
var msg   = msg || 'Error on Request';

Non sta solo controllando se il titolo / msg è stato fornito, ma anche se uno di essi è falso . vale a dire una delle seguenti:

  • falsa.
  • 0 (zero)
  • "" (stringa vuota)
  • nullo.
  • non definito.
  • NaN (un valore numerico speciale che significa Not-a-Number!)

Quindi in linea

var title = title || 'Error';

Se il titolo è veritiero (ovvero non falsa, quindi title = "titleMessage" ecc.), Allora l'operatore booleano OR (||) ha trovato un valore "vero", il che significa che valuta vero, quindi cortocircuita e ritorna il vero valore (titolo).

Se il titolo è falso (cioè uno dell'elenco sopra), l'operatore booleano OR (||) ha trovato un valore "falso" e ora deve valutare l'altra parte dell'operatore, "Errore", che valuta vero , e quindi viene restituito.

Sembrerebbe anche (dopo una breve sperimentazione sulla console di firebug) se entrambi i lati dell'operatore valutano come falso, restituisce il secondo operatore "falso".

vale a dire

return ("" || undefined)

restituisce indefinito, probabilmente per consentire all'utente di utilizzare il comportamento richiesto in questa domanda quando si tenta di impostare il titolo / messaggio predefinito su "". cioè dopo aver corso

var foo = undefined
foo = foo || ""

foo verrebbe impostato su ""


5

operatore a doppio tubo

questo esempio è utile?

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

può anche essere

var section = document.getElementById('special') || document.getElementById('main');

4

Per aggiungere qualche spiegazione a tutto ciò che ho detto prima di me, dovrei darti alcuni esempi per comprendere i concetti logici.

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

Significa che se il lato sinistro viene valutato come un'istruzione vera, verrà terminato e il lato sinistro verrà restituito e assegnato alla variabile. in altri casi il lato destro verrà restituito e assegnato.

E l' operatore ha la struttura opposta come di seguito.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh

3

|| è l'operatore booleano OR. Come in JavaScript, undefined, null, 0, false sono considerati valori falsi .

Significa semplicemente

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"

2

Citazione: "Cosa significa il costrutto x = x || y?"

Assegnare un valore predefinito.

Ciò significa fornire un valore predefinito da y a x , nel caso in cui x sia ancora in attesa del suo valore ma non lo abbia ancora ricevuto o sia stato deliberatamente omesso per tornare a un valore predefinito.


Questo è il significato esatto del costrutto e l'unico significato di esso. Ed era ampiamente come una subroutine nella scrittura di funzioni che potevano essere recuperate come prototipi, funzioni autonome e anche come metodi presi in prestito da applicare su un altro elemento. Dove il suo principale e unico dovere era modificare il riferimento dell'obiettivo. Esempio: function getKeys(x) { x = x || this ; .... }che potrebbe essere usato senza modifiche come funzione autonoma, come metodo di proprietà nei prototipi e come metodo di un elemento che può ottenere un altro elemento come argomento come `[element] .getKeys (anotherElement);`
Bekim Bacaj

-5

E devo aggiungere un'altra cosa: questa scorciatoia è un abominio. Utilizza in modo improprio un'ottimizzazione accidentale dell'interprete (non preoccuparsi della seconda operazione se la prima è veritiera) per controllare un compito. Tale uso non ha nulla a che fare con lo scopo dell'operatore. Non credo che dovrebbe mai essere usato.

Preferisco l'operatore ternario per l'inizializzazione, ad es.

var title = title?title:'Error';

Questo utilizza un'operazione condizionale di una riga per il suo scopo corretto. Gioca ancora a giochi sgradevoli con sincerità, ma questo è Javascript per te.

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.