Чи має JavaScript оцінку “короткого замикання”?


101

Я хотів би знати, чи має JavaScript оцінку "короткого замикання", як && Operator у C #. Якщо ні, я хотів би знати, чи є якийсь обхідний шлях, який має сенс прийняти.


2
Ласкаво просимо. Я додав https://www.google.com/search?q=site:stackoverflow.com+%sяк ярлик пошуку (Chrome / Firefox), щоб пришвидшити пошук.
Роб W

Також тут відповідь на моє запитання developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GibboK

Відповіді:


118

Так, JavaScript має оцінку "короткого замикання".

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

ДЕМО в прямому ефірі

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

ДЕМО в прямому ефірі


8
Отже, коротке замикання - це стандарт у JS?
GibboK

1
Дякую gdoron, будь ласка, допоможіть мені зрозуміти ... у C # у мене також є двійковий оператор like &, тому обидва операнди повинні бути істинними, щоб пройти, а не && в C
GibboK

1
@GibboK. Тоді, очевидно, Short-circuitз цим логічним оператором бути не може . Просто спробуйте самі. Використовуйте мою демонстрацію.
gdoron підтримує Моніку

2
@GibboK: Ознайомтеся з цим посиланням на оператора . І так, в JS також є двійковий оператор AND.
Бергі,

5
@GibboK. ТАК у стандарті! Але хороший коментар, як за часів магії компіляції JIT у реалізаціях javascript, насправді хочеться знати, чи є щось «стандартним», або потенційно підлягає реалізації. Те , як оператор умови з двійковими логічними операторами обчислюються і (коротке Curcuit) є стандартним поведінкою ecma-international.org/ecma-262/5.1/#sec-11.11
humanityANDpeace

23

Ця відповідь детально описує, як працює в JavaScript, з усіма причепами, а також відповідними темами, такими як пріоритет оператора, якщо ви шукаєте швидке визначення і вже розумієте, як працює коротке замикання, я б рекомендував перевірити інші відповіді.


Те, що ми (думали, що ми) знали до цього часу:

Спочатку давайте перевіримо поведінку, яку ми всі знайомі, всередині if()блоку, де ми використовуємо, &&щоб перевірити, чи є ці дві речі true:

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

Тепер ваш перший інстинкт, мабуть, полягає в тому, щоб сказати: "Ах, так, досить просто, код виконує оператор, якщо обидва expr1і expr2оцінюються як true"

Ну, так і ні. Ви технічно правильні, саме таку поведінку ви описали, але це не зовсім так, як оцінюється код, і нам потрібно буде глибше заглибитися, щоб повністю зрозуміти.


Як саме інтерпретується &&та ||?

Пора заглянути "під капот розглянемо цей практичний приклад:

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);

Ну результат 260... але чому? Щоб отримати відповідь, нам слід зрозуміти, як працює оцінка короткого замикання.

За визначенням MDN&& оператор expr1 && expr2виконується followingly:

Якщо expr1їх можна перетворити true, повертається expr2; інше, повертається expr1.

Отже, це означає, що на нашому практичному прикладі const resоцінюється наступним чином:

  1. Виклик expr1-sanitise(0xFF)
  2. 0xFF є дійсним шістнадцятковим числом для 250, інакше я б повернув NaN
  3. expr1Повернув «truthy» значення, час виконання expr2 ( в іншому випадку я б зупинити , як NaNце falsy)
  4. Оскільки userinputце істинний (число), я можу додати +5до нього
  • "Істинно" означає, що вираз можна оцінити як істинний. Ось список truthy і falsy виразів.

Отже, тут ми змогли уникнути додаткових ifблоків та подальших isNaNперевірок простим використанням &&оператора.


Як це насправді працює:

До теперішнього часу ми повинні мати принаймні уявлення про те, як працюють оператори. Загальне правило:

  • (some falsy expression) && expr оцінить до хибного виразу
  • (some truthy expression) || expr буде оцінювати до правдивого виразу

Ось ще кілька прикладів для кращого розуміння:

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


Остання остання настирлива, але дуже важлива річ [Пріоритет оператора]:

Приємно, сподіваємось, ви звикли! Останнє, що нам потрібно знати, це правило про пріоритет оператора, тобто:

  • &&Оператор завжди виконується до ||оператора.

Розглянемо наступний приклад:

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

Це повернеться як, можливо, заплутано для когось як a(). Причина досить проста, це просто наш погляд, який нас як би обманює, тому що ми звикли читати зліва направо. Давайте розберемо те, console.log()що не, і зосередимось виключно на оцінці

true || false && false

Тепер, щоб обернути голову навколо цього:

  1. Ми сказали, що &&оператор має пріоритет, тому він оцінюється як перший. Щоб допомогти нам краще уявити оцінку, подумайте про визначення

    expr1 && expr2

    Де:

    • expr2 є false
    • expr1 є true || false
  2. Отже, це була хитра частина, тепер true || falseоцінюється ( expr1- ліва сторона &&).

    • Враховуючи, що ||оператор зупиняє виконання, якщо expr1 || expr2in expr1вважає істинним, expr1виконується і виконання коду.
  3. Повернене значення: true

Ну .. це було досить складно, все через кілька дивних правил та семантики. Але пам’ятайте, ви завжди можете уникнути переваги оператора за допомогою ()- так само, як і в математиці

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


Я б 1) не використовував слово "компілятор". "двигун" є більш точним. 2) Чи не говорити expr1і expr2 чи condition1або незалежно від того , що це просто помилка. Визначтесь з одним, ви також можете ввести локальні змінні, наприклад. const expr1 = true; if(expr1 && ...)
Йонас

@JonasWilms дякую за вступ, відповідні зміни внесено.
Самуель

1
Це все ще не відповідає безпосередньо на поставлене запитання.
Кевін Б,

7
Це найкраща "чудова відповідь, яка прямо не відповідає на питання", яку я коли-небудь бачив ...
Херардо Фуртадо,

1
Це правильна відповідь із глибоким поясненням, вона повинна бути позначена як прийнята та підтримана набагато більше, ніж зараз!
Олександр Кім
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.