Wyjaśnienie przypisania zmiennych JavaScript OR (||)

351

Biorąc pod uwagę ten fragment kodu 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

Czy ktoś może mi wyjaśnić, jak nazywa się ta technika (najlepiej zgaduję w tytule tego pytania!)? I jak / dlaczego to działa dokładnie?

Rozumiem, że zmiennej fzostanie przypisana najbliższa wartość (od lewej do prawej) pierwszej zmiennej, która ma wartość, która nie jest ani zerowa, ani niezdefiniowana, ale nie udało mi się znaleźć wielu materiałów referencyjnych na temat tej techniki i mieć widziałem, że dużo zużyło.

Czy ta technika jest specyficzna dla JavaScript? Wiem, że zrobienie czegoś podobnego w PHP spowoduje fprawdziwą wartość boolowską, a nie wartość dsamego siebie.

chattsm
źródło
4
Stare pytanie, ale dotyczące PHP, istnieje konstrukt można użyć: $f=$a or $f=$b or $f=$c; // etc. PHP ma zarówno ||operatora, jak i oroperatora, którzy wykonują tę samą pracę; jednak orjest oceniany po przypisaniu, podczas gdy ||jest oceniany wcześniej. To również daje perlish styl$a=getSomething() or die('oops');
Manngo
1
W PHP 5.3 możesz pominąć środkową część operatora trójskładnikowego, więc bazując na tym ... Możesz również przyciąć to nieco krócej do czegoś takiego: $f = $a ?: $b ?: $c;
Rei
1
Od PHP 7 możesz ??do tego użyć . $a = $b ?? 'default'
Spencer Ruskin
@SpencerRuskin tak $azostanie przypisana wartość $b, jeśli $bjest prawdą, inne 'default'?
oldboy
Zgadza się. Spójrz na sekcję zerowego operatora koalescencyjnego na tej stronie: php.net/manual/en/migration70.new-features.php
Spencer Ruskin

Odpowiedzi:

212

Zobacz ocenę zwarciem za wyjaśnienie. Jest to powszechny sposób wdrażania tych operatorów; nie jest unikalny dla JavaScript.

rozwijać
źródło
57
Pamiętaj tylko o „gotcha”, która oznacza, że ​​ostatnia zawsze zostanie przypisana, nawet jeśli wszystkie są niezdefiniowane, zerowe lub fałszywe. Ustawienie czegoś, co wiesz, nie jest fałszywe, zerowe lub niezdefiniowane na końcu łańcucha to dobry sposób na zasygnalizowanie, że nic nie znaleziono.
Erik Reppen
Widziałem tę technikę od lat, ale wtedy uderzyło mnie to, kiedy chciałem jej użyć, że wynik wyrażenia nie jest przestawiony na wartość boolowską. Nie możesz później if( true == f ). Jeśli w f została zapisana liczba całkowita, to test zawsze zwróci false.
9
Właściwie możesz to zrobić if(true == f) , co jest takie samo jak if(f): test przejdzie. Jeśli chcesz również przetestować typ z fużyj ścisłego porównania: if(true === f), który zakończy się niepowodzeniem rzeczywiście.
Alsciende
5
Tak, ocena zwarcia jest powszechna. Różnica polega jednak na tym, że JavaScript zwraca ostatnią wartość, która zatrzymała wykonanie. @ Odpowiedź Anuraga znacznie lepiej wyjaśnia.
Ben.12
nie jestem pewien, czy to najlepsze wytłumaczenie dla początkujących. Polecam: javascript.info/logical-operators
csguy
198

Służy to do przypisania wartości domyślnej , w tym przypadku wartości y, jeśli xzmienna jest fałszem .

Operatory boolowskie w JavaScript mogą zwracać operand i nie zawsze wynik boolowski, jak w innych językach.

Operator logiczny OR (|| ) zwraca wartość drugiego operandu, jeśli pierwszy jest fałszem, w przeciwnym razie zwracana jest wartość pierwszego operandu.

Na przykład:

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

Wartości fałszowania to te, które zmuszają się, falsegdy są używane w kontekście logicznym, i są nimi0 , null, undefined, pusty ciąg, NaNi oczywiście false.

CMS
źródło
1
+1 Czy jest taki inny operator? Lub jest ||wyłączny.
OscarRyz
9
@ Wsparcie (@Oscar): &&Operator logiczny ma podobne zachowanie, zwraca wartość pierwszego operandu, jeśli sam w sobie jest fałszem, i zwraca wartość drugiego operandu, tylko jeśli pierwszy jest prawdziwy , np. ("foo" && "bar") == "bar"I(0 && "bar") == 0
CMS
12
Falsy to w rzeczywistości termin techniczny.
ChaosPandion
8
W tym poście dowiedzieliśmy się o ||, &&, „Falsy” i „Truly”. Najlepsza odpowiedź z „ukrytymi” prezentami.
Alex,
4
@Alex NB: „Truthy” (! „Truly”)
Wyboisty
183

Javacript używa oceny zwarcia dla operatorów logicznych ||i &&. Jednak różni się od innych języków tym, że zwraca wynik ostatniej wartości, która zatrzymała wykonanie, zamiast wartości a truelub false.

Poniższe wartości są uważane za falsy w JavaScript.

  • fałszywe
  • zero
  • "" (pusta struna)
  • 0
  • Nan
  • nieokreślony

Ignorując reguły pierwszeństwa operatora i upraszczając, poniższe przykłady pokazują, która wartość zatrzymała ocenę i w rezultacie została zwrócona.

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

Pierwsze 5 wartości w NaNgórę to fałsz, więc wszystkie są oceniane od lewej do prawej, dopóki nie osiągnie pierwszej wartości zgodnej z prawdą - "Hello"co sprawia, że ​​całe wyrażenie jest prawdziwe, więc żadne dalsze wyrażenie nie będzie oceniane i "Hello"zostanie zwrócone w wyniku wyrażenia . Podobnie w tym przypadku:

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

Wszystkie 5 pierwszych wartości są zgodne z prawdą i są poddawane ocenie, dopóki nie spełnią pierwszej wartości fałszowania ( null), co powoduje, że wyrażenie jest fałszywe, więc 2010nie jest już oceniane, i nullzostaje zwrócone w wyniku wyrażenia.

Podany przykład wykorzystuje tę właściwość JavaScript do wykonania zadania. Można go używać wszędzie tam, gdzie trzeba uzyskać pierwszą wartość prawdy lub fałszu spośród zestawu wartości. Poniższy kod przypisze wartość "Hello"do, bponieważ ułatwia przypisanie wartości domyślnej, zamiast przeprowadzania kontroli if-else.

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

Poniższy przykład można nazwać wykorzystaniem tej funkcji i uważam, że utrudnia to odczytanie kodu.

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

Wewnątrz alertu sprawdzamy, czy messagesjest to fałsz, a jeśli tak, to oceniamy i wracamy noNewMessagesText, w przeciwnym razie oceniamy i wracamy newMessagesText. Ponieważ w tym przykładzie jest to fałsz, zatrzymujemy się na noNewMessagesText i ostrzegamy "Sorry, you have no new messages.".

Anurag
źródło
36
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.
Według
1
@mastazi Tak, powinno być pogrubioną czcionką IMHO.
październik
6
Powinna być odpowiedź, pokazuje wartości wybrane w stosunku do przypadków testowych.
Dadan
Zgadzam się, to moja ulubiona odpowiedź, ponieważ dotyczy w szczególności problemów związanych z przypisywaniem zmiennych JavaScript. Ponadto, jeśli wybierzesz użycie trójki jako jednej z kolejnych zmiennych do testowania przypisania (po operatorze), musisz owinąć trójnik w nawiasy, aby ocena przypisania działała poprawnie.
Joey T.
to powinna być zaakceptowana odpowiedź
Alan
49

Zmienne JavaScript nie są wpisywane, więc f można przypisać wartość całkowitą, nawet jeśli została ona przypisana za pomocą operatorów logicznych.

f jest przypisywana najbliższa wartość, która nie jest równoważna wartości false . Tak więc wszystkie 0, false, null, undefined, są pomijane:

alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'
Alsciende
źródło
13
Nie zapomnij ''również równe fałsz w tym przypadku.
Brigand
Głosuj za wskazaniem tego, f is assigned the NEAREST valueco jest dość ważnym punktem tutaj.
steviejay
3
„Najbliższy” nie jest do końca prawdą, chociaż ma taki wygląd. ||Operator boolowski , będąc operatorem boolowskim, ma dwa operandy: lewą i prawą stronę. Jeśli lewa strona ||jest prawdą , operacja jest rozpatrywana na lewą, a prawa strona jest ignorowana. Jeśli lewa strona jest fałszem , rozwiązuje się na prawej stronie. Tak więc null || undefined || 4 || 0faktycznie rozwiązuje, do undefined || 4 || 0którego decyduje, do 4 || 0którego decyduje 4.
devios1
29

Nie ma w tym żadnej magii. Wyrażenia logiczne, takie jak, a || b || c || dsą leniwie oceniane. Interpeter szuka wartości a, jest niezdefiniowany, więc jest fałszywy, więc porusza się dalej, a następnie widzi, bktóra wartość jest pusta, co nadal daje fałszywy wynik, więc porusza się dalej, a następnie widzi c- tę samą historię. Wreszcie widzi di mówi „huh, to nie jest zero, więc mam swój wynik” i przypisuje go do zmiennej końcowej.

Ta sztuczka będzie działać we wszystkich dynamicznych językach, które wykonują leniwe zwarcie w wyrażeniach boolowskich. W językach statycznych nie będzie się kompilować (błąd typu). W językach, które chętnie oceniają wyrażenia logiczne, zwróci wartość logiczną (w tym przypadku true).

Marcin
źródło
6
W dość statycznym języku C # można użyć ?? operator á la: obiekt f = a ?? b ?? c ?? d ?? mi;
herzmeister
2
herzmeister - dzięki! Nie wiedziałem tego? operator może być połączony w C # i użyty w leniwych technikach oceny
Marek
3
Jak wspomniano w innym miejscu, ten ostatni dzostanie przypisany, niezależnie od tego, czy był nieważny / niezdefiniowany, czy nie.
BlackVegetable
Jedna drobna korekta: ||operator zawsze rozpoznaje operand po całej prawej stronie, gdy lewa strona jest fałszywa. Będąc operatorem typu boolean, widzi tylko dwa wejścia: lewą i prawą stronę. Analizator składniowy nie widzi ich jako szeregu terminów, więc tak naprawdę nie zatrzymuje się, gdy znajdzie pierwszą prawdziwą wartość, chyba że ta wartość jest również operandem lewej ręki innego ||.
devios1
8

To pytanie otrzymało już kilka dobrych odpowiedzi.

Podsumowując, ta technika wykorzystuje funkcję kompilacji języka. Oznacza to, że JavaScript „zwiera” ocenę operatorów boolowskich i zwróci wartość związaną z pierwszą niefałszową wartością zmiennej lub jakąkolwiek ostatnią zmienną. Zobacz wyjaśnienie Anuragu dotyczące wartości, które zostaną ocenione jako fałszywe.

Korzystanie z tej techniki nie jest dobrą praktyką z kilku powodów; jednak.

  1. Czytelność kodu: używa operatorów boolowskich, a jeśli zachowanie tego, jak ta kompilacja nie jest zrozumiana, to oczekiwany wynik byłby wartością boolowską.
  2. Stabilność: wykorzystuje funkcję kompilacji języka, która jest niespójna w wielu językach, dzięki czemu może być potencjalnie celem zmian w przyszłości.
  3. Udokumentowane funkcje: Istnieje istniejąca alternatywa, która spełnia tę potrzebę i jest spójna w większej liczbie języków. Byłby to operator trójskładnikowy:

    ()? wartość 1: wartość 2.

Użycie operatora trójskładnikowego wymaga nieco więcej pisania, ale wyraźnie rozróżnia między wyrażeniem logicznym, które jest oceniane, a przypisywaną wartością. Ponadto można go łączyć w łańcuchy, aby można było odtworzyć typy domyślnych przypisań wykonywane powyżej.

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
WSimpson
źródło
potentially be targeted for change in the future.tak, ale nie dotyczy to javascript.
Dadan
Przybyłem tutaj i zobaczyłem wszystkie powyższe odpowiedzi i pomyślałem sobie, że coś po prostu odwróciło uwagę od zadania. Właśnie czytałem Czysty kod Roberta C. Martina i ten typ zadania zdecydowanie narusza zasadę „Nie mam żadnych skutków ubocznych” ... podczas gdy sam autor stwierdza, że ​​jego książka jest tylko jedną z wielu technik generowania dobrego kodu, ja nadal był zaskoczony, że nikt inny nie sprzeciwił się takiemu zadaniu. +1
Albert Rothman
Dziękuję za odpowiedź. Myślę, że więcej osób musi brać pod uwagę skutki uboczne podczas pisania kodu, ale dopóki ktoś nie poświęci dużo czasu na utrzymanie kodu innej osoby. Często tego nie rozważają.
WSimpson
1
Naprawdę uważasz, że potworność jest wyraźniejsza niż a || b || c || d || e?
devios1
1
@AlbertRothman Nie widzę żadnych skutków ubocznych. Nic się nie mutuje. Jest to po prostu skrót dla koalescencji zerowej, co jest dość powszechną cechą w wielu językach.
devios1
7

Zwraca wyjściową pierwszą prawdziwą wartość .

Jeśli wszystkie są fałszywe, zwróć ostatnią fałszywą wartość.

Przykład:-

  null || undefined || false || 0 || 'apple'  // Return apple
Arshid KV
źródło
4

Ustawia nową zmienną ( z) na wartość x„prawda” (niezerowa, poprawny obiekt / tablica / funkcja / cokolwiek to jest) lub yinaczej. Jest to stosunkowo powszechny sposób podawania wartości domyślnej w przypadku, xgdy nie istnieje.

Na przykład, jeśli masz funkcję, która pobiera opcjonalny parametr wywołania zwrotnego, możesz podać domyślne wywołanie zwrotne, które nic nie robi:

function doSomething(data, callback) {
    callback = callback || function() {};
    // do stuff with data
    callback(); // callback will always exist
}
Matthew Crumley
źródło
1

Oznacza to, że jeśli xjest ustawiony, wartość dla zbędzie x, w przeciwnym razie, jeśli yzostanie ustawiony, wówczas jego wartość zostanie ustawiona jako zwartość.

to to samo co

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

Jest to możliwe, ponieważ operatory logiczne w JavaScript nie zwracają wartości boolowskich, ale wartość ostatniego elementu potrzebnego do zakończenia operacji (w zdaniu OR byłaby to pierwsza nie-fałszywa wartość, w zdaniu AND byłaby to ostatnia ). Jeśli operacja się nie powiedzie, falsezostanie zwrócona.

Andris
źródło
5
To jest źle! if (x) {z = x; } else {z = y;} jeśli pierwsza wartość to false, druga wartość jest zawsze przypisywana niezależnie od rzeczywistej wartości.
evilpie
Tyle że myślę, że po prostu przypisuje y do z, jeśli x jest fałszem . W ten sposób działa dla mnie w FF, oczywiście, może to również zależeć od implementacji.
tvanfosson
7
Ostatnia część o zwróceniu wartości false nie jest prawdą (nie jest zamierzona gra słów). Jeśli pierwszą wartością jest falsey, ||operator zwraca drugą wartość, niezależnie od tego, czy jest zgodna z prawdą, czy nie.
Matthew Crumley
-1. Twój równoważny fragment kodu jest dokładny, ale ważne jest, aby zustawić wartość, xjeśli ta wartość jest prawdziwa . W przeciwnym razie zostanie ustawiona wartość y. Oznacza to, że jeśli xustawiono na przykład 0pusty ciąg "", nie robi to, co mówisz, ponieważ te wartości są fałszywe .
Daniel Cassidy
1

Nazywa się to operatorem zwarcia.

Ocena zwarcia mówi, że drugi argument jest wykonywany lub oceniany tylko wtedy, gdy pierwszy argument nie jest wystarczający do ustalenia wartości wyrażenia. gdy pierwszy argument funkcji OR (||) ma wartość true, całkowita wartość musi być prawdziwa.

Może być również użyty do ustawienia domyślnej wartości argumentu funkcji.`

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`
Vijay
źródło
0

Ocenia X, a jeśli X nie ma wartości NULL, pusty łańcuch lub 0 (logiczny fałsz), wówczas przypisuje go do z. Jeśli X ma wartość NULL, pusty ciąg lub 0 (logiczny fałsz), wówczas przypisuje y do z.

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

Wyjdzie „bob”;

tvanfosson
źródło
Powinieneś wyjaśnić, co rozumiesz przez „pusty”. Puste łańcuchy zmuszają do false, ale puste tablice lub obiekty zmuszają true.
Daniel Cassidy
@Daniel „null, empty or 0” - null miałoby zastosowanie do tablic i obiektów. Ale punkt.
tvanfosson
0

Zgodnie z postem na blogu Billa Higginsa ; idiom logiczny OR przypisania JavaScript (luty 2007), to zachowanie jest prawdziwe od wersji 1.2 (przynajmniej)

Sugeruje także inne zastosowanie (cytowane): „ lekka normalizacja różnic między przeglądarkami

// determine upon which element a Javascript event (e) occurred
var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
Alon Brontman
źródło