Czy JavaScript ma ocenę „Zwarcia”?

101

Chciałbym wiedzieć, czy JavaScript ma ocenę „zwarcia”, taką jak && Operator w C #. Jeśli nie, chciałbym wiedzieć, czy istnieje obejście, które ma sens.

GibboK
źródło
2
Nie ma za co. Dodałem https://www.google.com/search?q=site:stackoverflow.com+%sjako skrót wyszukiwania (Chrome / Firefox), aby przyspieszyć wyszukiwanie.
Rob W.
Tutaj również odpowiedź na moje pytanie developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GibboK
Dalsze przydatne zasoby: || pytanie ewaluacyjne Pytanie ewaluacyjne &&
Samuel Hulla

Odpowiedzi:

118

Tak, JavaScript ma ocenę „zwarcia”.

if (true == true || foo.foo){
    // Passes, no errors because foo isn't defined.
}

DEMO na żywo

if (false && foo.foo){
    // Passes, no errors because foo isn't defined.
}

DEMO na żywo

gdoron wspiera Monikę
źródło
8
Czyli zwarcie to standard w JS?
GibboK,
1
Dzięki gdoron, pomóż mi zrozumieć ... w C # mam również operator binarny taki jak &, więc oba operand muszą być prawdziwe do przejścia, zamiast tego z && w C
GibboK
1
@GibboK. Wtedy oczywiście nie może być Short-circuitz tym operatorem logicznym. Po prostu spróbuj sam. Skorzystaj z mojego demo.
gdoron wspiera Monikę
2
@GibboK: Sprawdź odniesienie do operatora . I tak, w JS jest również operator binarny AND.
Bergi
5
@GibboK. TAK w standardzie! Ale dobry komentarz, tak jak w czasach magii kompilacji JIT w implementacjach javascript, naprawdę chce się wiedzieć, czy coś jest „standardem”, czy potencjalnie podlega implementacji. Sposób oświadczenie stan z binarne operatory logiczne jest oceniane i (krótki curcuit) jest standardowym zachowaniem ecma-international.org/ecma-262/5.1/#sec-11.11
humanityANDpeace
24

Ta odpowiedź zawiera bardzo szczegółowe informacje na temat tego, jak to zrobić działa w JavaScript, ze wszystkimi gotcha, a także odpowiednimi motywami, takimi jak pierwszeństwo operatorów, jeśli szukasz szybkiej definicji i już rozumiesz, jak działa zwarcie, polecam sprawdzenie innych odpowiedzi.


Co (myśleliśmy, że) wiedzieliśmy do tej pory:

Najpierw przyjrzyjmy się zachowaniu, które wszyscy znamy, wewnątrz if()bloku, w którym używamy &&do sprawdzenia, czy te dwie rzeczy są true:

if (true && true) {
   console.log('bar');
} 

Twoim pierwszym odruchem jest prawdopodobnie powiedzenie: „Ach tak, całkiem proste, kod wykonuje instrukcję, jeśli oba expr1i expr2są oceniane jako true

Cóż, tak i nie. Jesteś technicznie poprawny, to jest zachowanie, które opisałeś, ale nie tak dokładnie jest oceniany kod i będziemy musieli zagłębić się głębiej, aby w pełni zrozumieć.


Jak dokładnie jest interpretowane &&i ? ||:

Czas zajrzeć „pod maskę silnik ”. Rozważmy ten praktyczny przykład:

function sanitise(x) {
  if (isNaN(x)) {
    return NaN;
  }
  return x;
}

let userinput = 0xFF; // as an example
const res = sanitise(userinput) && userinput + 5

console.log(res);

Wynik jest taki 260… ale dlaczego? Aby uzyskać odpowiedź, musimy zrozumieć, jak działa ocena zwarcia.

Przez Definicja MDN&& operator expr1 && expr2jest wykonywany followingly:

Jeśli expr1można przekonwertować na true, zwraca expr2; w przeciwnym razie zwraca expr1.

Oznacza to, że w naszym praktycznym przykładzie wartość const resjest oceniana w następujący sposób:

  1. Wzywam expr1-sanitise(0xFF)
  2. 0xFF jest prawidłową liczbą szesnastkową dla 250, w przeciwnym razie zwróciłbym NaN
  3. expr1Zwrócona wartość „truthy”, czas na wykonanie expr2 (inaczej wpadnę jak NaNto falsy)
  4. Ponieważ userinputjest truthy (liczba), mogę dodać +5do niego
  • „Prawda” oznacza, że ​​wyrażenie można ocenić jako prawdziwe. Oto lista prawdziwych i fałszywych wyrażeń.

Więc tutaj mogliśmy uniknąć dodatkowych ifblokad i dalszych isNaNkontroli dzięki prostemu użyciu &&operatora.


Jak to naprawdę działa:

Do tej pory powinniśmy mieć przynajmniej obraz tego, jak plik operatorzy pracują. Uniwersalna zasada brzmi:

  • (some falsy expression) && expr oceni do fałszywego wyrażenia
  • (some truthy expression) || expr oceni do prawdziwego wyrażenia

Oto kilka dalszych przykładów dla lepszego zrozumienia:

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() && b() ){
     console.log('foobar'); 
}

//Evaluates a() as false, stops execution.

function a() { console.log('a'); return false; }
function b() { console.log('b'); return true; }

if ( a() || b() ){
     console.log('foobar'); 
}

/* 1. Evaluates a() as false
   2. So it should execute expr2, which is `b()`
   3. b() returned as true, executing statement `console.log('foobar');`
*/


Ostatnia nieznośna, ale bardzo ważna rzecz [Pierwszeństwo operatora]:

Fajnie, miejmy nadzieję, że zrozumiesz to! Ostatnią rzeczą, którą musimy wiedzieć, jest zasada dotycząca pierwszeństwa operatorów, czyli:

  • &&Operator jest zawsze wykonywany przed ||operatora.

Rozważmy następujący przykład:

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log(a() || b() && c());

// returns a() and stops execution

To powróci jako, być może myląco dla niektórych, jak a(). Rozum jest dość prosty, tylko wzrok nas zwodzi, ponieważ jesteśmy przyzwyczajeni do czytania od lewej do prawej. Wyjmijmy, console.log()a co nie, i skupmy się wyłącznie na ocenie

true || false && false

Teraz, aby owinąć głowę wokół tego:

  1. Powiedzieliśmy, że &&operator ma pierwszeństwo, więc jest oceniany jako pierwszy. Aby pomóc nam lepiej wyobrazić sobie ocenę, pomyśl o definicji

    expr1 && expr2

    Gdzie:

    • expr2 jest false
    • expr1 jest true || false
  2. Więc to była trudna część, teraz true || falsejest oceniana ( expr1- lewa strona &&).

    • Biorąc pod uwagę, że ||operator zatrzymuje wykonywanie, jeśli expr1 || expr2w expr1oszacuje się jako prawda, expr1jest wykonywany, a wykonywanie kodu zatrzymuje się.
  3. Zwracana wartość to true

Cóż… to było dość trudne, wszystko z powodu kilku dziwnych reguł i semantyki. Pamiętaj jednak, że zawsze możesz uniknąć pierwszeństwa operatora za pomocą ()- tak jak w matematyce

function a() { console.log('a'); return true;}
function b() { console.log('b'); return false;}
function c() { console.log('c'); return false;}

console.log((a() || b()) && c());

/* 1. The () escape && operator precedence
   2. a() is evaluated as false, so expr2 (c()) to be executed
   3. c()  
*/

Samuel Hulla
źródło
Nie użyłbym 1) słowa „kompilator”. „silnik” jest dokładniejszy. 2) Nie mów o expr1a expr2 lub condition1czy cokolwiek innego, to jest po prostu mylące. Zdecyduj się na jedną, możesz też wprowadzić zmienne lokalne, np. const expr1 = true; if(expr1 && ...)
Jonas Wilms
@JonasWilms dzięki za wkład, odpowiednio poprawił odpowiedź.
Samuel Hulla
1
To nadal nie odpowiada bezpośrednio na zadane pytanie.
Kevin B
7
To najlepsza „świetna odpowiedź, która nie odpowiada wprost na pytanie” , jaką kiedykolwiek widziałem ...
Gerardo Furtado
1
To jest właściwa odpowiedź z głębokim wyjaśnieniem, powinna być oznaczona jako zaakceptowana i przegłosowana znacznie bardziej niż obecnie!
Alexander Kim