Was bedeutet das Konstrukt x = x || y meine?

250

Ich debugge JavaScript und kann nicht erklären, was dies ||bewirkt.

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

Kann mir jemand einen Hinweis geben, warum dieser Typ benutzt var title = title || 'ERROR'? Ich sehe es manchmal auch ohne varErklärung.

opHASnoNAME
quelle
44
Die Leute haben dies bereits beantwortet ... aber seien Sie sich der Tatsache sehr bewusst, dass der zweite Wert gewählt wird, wenn der erste Wert falsynicht NUR ist undefined. Die Häufigkeit, die ich gesehen habe doWeDoIt = doWeDoIt || true, reicht aus, um mich zum Weinen zu bringen. (dh doWeDoItwird es jetzt nie sein false)
Matt
4
Für diejenigen mit Erfahrung mit C # entspricht der Doppelrohroperator dem Null-Koaleszenz-Operator ??. Javascript wertet Nicht-Null-Objekte wie true (oder besser Null-Objekte als falsch aus)
usr-local-ΕΨΗΕΛΩΝ
3
Fühlen Sie sich nicht schlecht - JS ist die einzige doofe Sprache, die diese schreckliche Codierung zulässt ... und lehrt, dass es richtig ist, jede Funktion in Codezeilen zu verschachteln und wegzuwerfen, um sie ein zweites Mal verfügbar und unbrauchbar zu machen. :) Ich bin 30 Jahre im Codieren und habe JS bis vor kurzem selbst nicht berührt. Ich spüre, dass dein Schmerz alles ist, was ich sagen kann. Halte ein "macht keinen Sinn, es ist nur in JS" Cheetsheet griffbereit, es ist der einzige Weg, wie ich ' sind durchgekommen! :)
Collin Chaffin
1
Bitte erwägen Sie, die akzeptierte Antwort in meine Antwort zu ändern .
Michał Perłakowski

Antworten:

210

Dies bedeutet, dass das titleArgument optional ist. Wenn Sie die Methode ohne Argumente aufrufen, wird der Standardwert von verwendet "Error".

Es ist eine Abkürzung zum Schreiben:

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

Diese Art von Kurztrick mit booleschen Ausdrücken ist auch in Perl üblich. Mit dem Ausdruck:

a OR b

es wird ausgewertet, trueob entweder aoder bist true. Wenn dies azutrifft, müssen Sie dies überhaupt nicht überprüfen b. Dies wird als boolesche Kurzschlussauswertung bezeichnet.

var title = title || "Error";

prüft grundsätzlich, ob titleausgewertet wird false. Wenn dies der Fall ist, wird es "zurückgegeben" "Error", andernfalls wird es zurückgegeben title.

Cletus
quelle
3
Tut mir leid, wählerisch zu sein, aber das Argument ist nicht optional, das Argument wird überprüft
mächtige Brötchen
4
Dies ist NICHT die Antwort und ich stimme dem letzten Kommentar zu, es ist nicht einmal optional. Kein Teil dieser Antwort ist korrekt, auch nicht die Perl-Referenz, da die Perl-Anweisung tatsächlich SENSE macht und auf eine völlig andere Weise bewertet wird. Das JS ist eine viel "konvertiertere" boolesche Logikmethode, die ich auch beim Lesen / Schreiben viel verwirrender finde. Die Antwort mit dem Titel "Was ist der Doppelrohrbetreiber?" Ist tatsächlich eine korrekte Antwort.
Collin Chaffin
198

Was ist der Doppelrohrbetreiber ( ||)?

Der Doppelrohroperator ( ||) ist der logische OROperator . In den meisten Sprachen funktioniert es folgendermaßen:

  • Wenn der erste Wert ist false, wird der zweite Wert überprüft. Wenn es so ist true, kehrt es zurück trueund wenn es so ist false, kehrt es zurück false.
  • Wenn der erste Wert ist true, wird immer zurückgegeben true, unabhängig vom zweiten Wert.

Im Grunde funktioniert es also wie folgt:

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

Wenn Sie immer noch nicht verstehen, schauen Sie sich diese Tabelle an:

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

Mit anderen Worten, es ist nur falsch, wenn beide Werte falsch sind.

Wie unterscheidet es sich in JavaScript?

JavaScript ist etwas anders, weil es eine lose getippte Sprache ist . In diesem Fall bedeutet dies, dass Sie einen ||Operator mit Werten verwenden können, die keine Booleschen Werte sind. Obwohl es keinen Sinn macht, können Sie diesen Operator beispielsweise mit einer Funktion und einem Objekt verwenden:

(function(){}) || {}

Was passiert da?

Wenn die Werte nicht boolesch sind, konvertiert JavaScript implizit in boolesche Werte . Es bedeutet , dass , wenn der Wert Falsey ist (zB 0, "", null, undefined(siehe auch alle Falsey Werte in JavaScript )), wird es als behandelt werden false; sonst wird es behandelt als true.

Das obige Beispiel sollte also geben true, weil leere Funktion wahr ist. Nun, das tut es nicht. Es gibt die leere Funktion zurück. Das liegt daran, dass der JavaScript- ||Operator nicht so funktioniert, wie ich es am Anfang geschrieben habe. Es funktioniert folgendermaßen:

  • Wenn der erste Wert falsey ist , wird der zweite Wert zurückgegeben .
  • Wenn der erste Wert wahr ist , wird der erste Wert zurückgegeben .

Überrascht? Eigentlich ist es "kompatibel" mit dem traditionellen ||Operator. Es könnte wie folgt geschrieben werden:

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

Wenn Sie einen wahrheitsgemäßen Wert als übergeben x, xwird ein wahrheitsgemäßer Wert zurückgegeben. Wenn Sie es später in ifAbschnitt verwenden:

(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*/));

du bekommst "Either x or y is truthy.".

Wenn xes falsch eitherXorYwäre , wäre es y. In diesem Fall würden Sie das "Either x or y is truthy."Wenn bekommen, das ywahr ist; sonst würdest du bekommen "Neither x nor y is truthy".

Die eigentliche Frage

Wenn Sie nun wissen, wie der ||Operator funktioniert, können Sie wahrscheinlich selbst erkennen, was dies x = x || ybedeutet. Wenn xes wahr ist, xwird zugewiesen x, so dass eigentlich nichts passiert; sonst yist zugeordnet x. Es wird häufig verwendet, um Standardparameter in Funktionen zu definieren. Es wird jedoch oft als schlechte Programmierpraxis angesehen , da es Sie daran hindert, einen Falsey-Wert (der nicht unbedingt undefinedoder ist null) als Parameter zu übergeben. Betrachten Sie folgendes Beispiel:

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

Es sieht auf den ersten Blick gültig aus. Was würde jedoch passieren, wenn Sie falseals flagAParameter übergeben würden (da es boolesch ist, dh trueoder sein kann false)? Es würde werden true. In diesem Beispiel gibt es keine Möglichkeit, festgelegt flagAzu false.

Es wäre eine bessere Idee, explizit zu prüfen, ob dies so flagAist undefined:

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

Obwohl es länger ist, funktioniert es immer und es ist leichter zu verstehen.


Sie können die ES6-Syntax auch für Standardfunktionsparameter verwenden. Beachten Sie jedoch, dass dies in älteren Browsern (wie dem IE) nicht funktioniert. Wenn Sie diese Browser unterstützen möchten, sollten Sie Ihren Code mit Babel transpilieren .

Siehe auch Logische Operatoren auf MDN .

Michał Perłakowski
quelle
13
+1 - bei weitem die richtigste und vollständigste Antwort. Und für diejenigen mit dieser Frage (einige von uns erfahrenen Programmierern, die neu bei JS sind) sollte sich das Beste aus dieser gesamten Antwort auf diese Zeile konzentrieren: "Obwohl es keinen Sinn macht", weil diese "lose getippte" einfach nie Sinn ergibt für diejenigen von uns, die ohne sie aufgewachsen sind. Für uns ist ein boolescher Operator genau das und NUR das ...... und wer auch immer jemals gedacht hat, dass es eine gute Idee wäre, beim Lesen / Schreiben von Code anzuhalten und über eine verrückte Konvertierung von nicht-booleschen Werten in boolesche Werte nachzudenken Ich habe vergessen, an diesem Tag ihre Medikamente einzunehmen! :)
Collin Chaffin
2
+1, kurz gesagt: title = title || 'Error'bedeutetif (title) { title = title; } else { title = 'Error'; }
Andre Elrico
Ich bin eigentlich nicht mit der Zeile "obwohl es keinen Sinn macht" einverstanden. Ich verstehe, dass die Zeile zum Beispiel nicht in C kompiliert werden würde, aber es ist gut verstanden, wenn Sie zum Beispiel von Ruby oder sogar von Groovy stammen. In Ruby könnte man es noch kürzer ausdrücken, als title ||= 'Error'.
Elliot Nelson
28

Wenn der Titel nicht festgelegt ist, verwenden Sie 'ERROR' als Standardwert.

Allgemeiner:

var foobar = foo || default;

Liest: Stellen Sie foobar auf foooder default. Sie könnten dies sogar viele Male verketten:

var foobar = foo || bar || something || 42;
Ericteubert
quelle
1
Ich fand es verwirrend, weil die Variablen den gleichen Namen haben. Viel einfacher, wenn sie es nicht tun.
Norbert Norbertson
14

Erklären Sie dies ein wenig mehr ...

Der ||Operator ist der logische orOperator. Das Ergebnis ist wahr, wenn der erste Teil wahr ist, und es ist wahr, wenn der zweite Teil wahr ist, und es ist wahr, wenn beide Teile wahr sind. Zur Verdeutlichung steht hier eine Tabelle:

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

Jetzt etwas hier bemerken? Wenn Xwahr ist, ist das Ergebnis immer wahr. Wenn wir also wissen, dass Xdas stimmt, müssen wir das überhaupt nicht überprüfen Y. Viele Sprachen implementieren daher "Kurzschluss" -Auswertungsgeräte für logisches or(und logisches andKommen aus der anderen Richtung). Sie überprüfen das erste Element und wenn das stimmt, kümmern sie sich überhaupt nicht darum, das zweite zu überprüfen. Das Ergebnis (logisch ausgedrückt) ist das gleiche, aber in Bezug auf die Ausführung gibt es möglicherweise einen großen Unterschied, wenn die Berechnung des zweiten Elements teuer ist.

Was hat das mit Ihrem Beispiel zu tun?

var title   = title || 'Error';

Schauen wir uns das an. Das titleElement wird an Ihre Funktion übergeben. Wenn Sie in JavaScript keinen Parameter übergeben, wird standardmäßig ein Nullwert verwendet. Auch in JavaScript wird Ihre Variable von den logischen Operatoren als falsch angesehen, wenn sie ein Nullwert ist. Wenn diese Funktion mit einem angegebenen Titel aufgerufen wird, handelt es sich um einen nicht falschen Wert, der der lokalen Variablen zugewiesen wird. Wenn es jedoch keinen Wert erhält, ist es ein Nullwert und somit falsch. Der logische orOperator wertet dann den zweiten Ausdruck aus und gibt stattdessen 'Fehler' zurück. Jetzt erhält die lokale Variable den Wert 'Fehler'.

Dies funktioniert aufgrund der Implementierung logischer Ausdrücke in JavaScript. Es wird kein korrekter boolescher Wert ( trueoder false) zurückgegeben, sondern der Wert, der nach einigen Regeln angegeben wurde, was als äquivalent trueund was als äquivalent angesehen wird false. Suchen Sie in Ihrer JavaScript-Referenz nach Informationen darüber, was JavaScript in booleschen Kontexten als wahr oder falsch ansieht.

NUR MEINE RICHTIGE MEINUNG
quelle
8

Double Pipe steht für logisches "ODER". Dies ist nicht wirklich der Fall, wenn der "Parameter nicht gesetzt" ist, da streng im Javascript, wenn Sie Code wie diesen haben:

function foo(par) {
}

Dann ruft an

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

sind nicht gleichwertig.

Double Pipe (||) wandelt das erste Argument in einen Booleschen Wert um. Wenn der resultierende Boolesche Wert wahr ist, führen Sie die Zuweisung aus, andernfalls wird der richtige Teil zugewiesen.

Dies ist wichtig, wenn Sie nach nicht festgelegten Parametern suchen.

Angenommen, wir haben eine Funktion setSalary mit einem optionalen Parameter. Wenn der Benutzer den Parameter nicht angibt, sollte der Standardwert 10 verwendet werden.

Wenn Sie die Prüfung wie folgt durchführen:

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

Dies führt zu einem unerwarteten Ergebnis bei einem Anruf wie

setSalary(0) 

Es wird weiterhin die 10 nach dem oben beschriebenen Ablauf eingestellt.

Juriy
quelle
8

Grundsätzlich wird geprüft, ob der Wert vor dem || liegt wird als wahr ausgewertet. Wenn ja, wird dieser Wert angenommen. Wenn nicht, wird der Wert nach || verwendet.

Werte, für die der Wert nach || angenommen wird (soweit ich mich erinnern kann):

  • nicht definiert
  • falsch
  • 0
  • '' (Null oder Null String)
Morfildur
quelle
1
false || null || undefiniert || 0 || '' || 'du hast null vergessen'
Dziamid
7

Obwohl die Antwort von Cletus richtig ist, sollten meines Erachtens weitere Details in Bezug auf "Auswertungen als falsch" in JavaScript hinzugefügt werden.

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

Überprüft nicht nur, ob title / msg angegeben wurde, sondern auch, ob einer von beiden falsch ist . dh eine der folgenden:

  • falsch.
  • 0 (Null)
  • "" (leerer String)
  • Null.
  • nicht definiert.
  • NaN (ein spezieller Zahlenwert, der Not-a-Number bedeutet!)

Also in der Schlange

var title = title || 'Error';

Wenn title wahr ist (dh nicht falsch, also title = "titleMessage" usw.), hat der boolesche OR (||) -Operator einen 'true'-Wert gefunden, was bedeutet, dass er als true ausgewertet wird, also kurzgeschlossen und zurückgegeben wird der wahre Wert (Titel).

Wenn der Titel falsch ist (dh einer der obigen Listen), hat der Boolesche OR-Operator (||) einen 'falschen' Wert gefunden und muss nun den anderen Teil des Operators 'Fehler' auswerten, der als wahr ausgewertet wird und wird daher zurückgegeben.

Es scheint auch (nach einigen schnellen Experimenten mit der Firebug-Konsole), wenn beide Seiten des Operators als falsch bewertet werden, wird der zweite "falsche" Operator zurückgegeben.

dh

return ("" || undefined)

Gibt undefiniert zurück. Dies dient wahrscheinlich dazu, dass Sie das in dieser Frage gestellte Verhalten verwenden können, wenn Sie versuchen, den Standardtitel / die Standardnachricht auf "" zu setzen. dh nach dem Laufen

var foo = undefined
foo = foo || ""

foo würde auf "" gesetzt sein

Azrantha
quelle
5

Doppelrohrbetreiber

ist dieses Beispiel nützlich?

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

kann auch sein

var section = document.getElementById('special') || document.getElementById('main');
wählen
quelle
4

Um allen vor mir Gesagten eine Erklärung hinzuzufügen, möchte ich Ihnen einige Beispiele geben, um logische Konzepte zu verstehen.

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

Dies bedeutet, wenn die linke Seite als echte Aussage ausgewertet wird, wird sie beendet und die linke Seite wird zurückgegeben und der Variablen zugewiesen. In anderen Fällen wird die rechte Seite zurückgegeben und zugewiesen.

Und der Bediener hat die entgegengesetzte Struktur wie unten.

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

|| ist der boolesche ODER-Operator. Wie in Javascript werden undefiniert, null, 0, falsch als falsche Werte betrachtet.

Es bedeutet einfach

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"
Shivang Gupta
quelle
2

Zitat: "Was bedeutet das Konstrukt x = x || y?"

Zuweisen eines Standardwerts.

Dies bedeutet, dass x ein Standardwert von y angegeben wird , falls x noch auf seinen Wert wartet, ihn aber noch nicht erhalten hat oder absichtlich weggelassen wurde, um auf einen Standardwert zurückzugreifen.

Bekim Bacaj
quelle
Das ist die genaue Bedeutung des Konstrukts und die einzige Bedeutung davon. Und es war eine Unterroutine zum Schreiben von Funktionen, die als Prototypen, eigenständige Funktionen und auch als geliehene Methoden abgerufen werden konnte, um auf ein anderes Element angewendet zu werden. Wo seine Haupt- und einzige Pflicht darin bestand, die Referenz des Ziels zu ändern. Beispiel: function getKeys(x) { x = x || this ; .... }Dies könnte ohne Änderung als eigenständige Funktion, als Eigenschaftsmethode in Prototypen und als Methode eines Elements verwendet werden, das ein anderes Element als Argument als "[Element] .getKeys (anotherElement)" erhalten kann.
Bekim Bacaj
-5

Und ich muss noch etwas hinzufügen: Diese Abkürzung ist ein Greuel. Es missbraucht eine versehentliche Interpreteroptimierung (die sich nicht um die zweite Operation kümmert, wenn die erste wahr ist), um eine Zuweisung zu steuern. Diese Verwendung hat nichts mit dem Zweck des Betreibers zu tun. Ich glaube nicht, dass es jemals benutzt werden sollte.

Ich bevorzuge den ternären Operator für die Initialisierung, z.

var title = title?title:'Error';

Dies verwendet eine einzeilige bedingte Operation für den richtigen Zweck. Es spielt immer noch unansehnliche Spiele mit Wahrhaftigkeit, aber das ist Javascript für Sie.

tqwhite
quelle