Есть ли у JavaScript оценка «короткого замыкания»?


101

Я хотел бы знать, есть ли в JavaScript оценка «короткого замыкания», такая как && Operator в C #. Если нет, я хотел бы знать, есть ли обходной путь, который имеет смысл принять.


2
Пожалуйста. Я добавил https://www.google.com/search?q=site:stackoverflow.com+%sв качестве ярлыка поиска (Chrome / Firefox) для ускорения поиска.
Rob W

Также здесь ответ на мой вопрос developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
GibboK 01

Дополнительные полезные ресурсы: || вопрос оценки && вопрос оценки
Самуэль

Ответы:


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 # у меня также есть бинарный оператор, например &, поэтому оба операнда должны быть верными для передачи, вместо этого с && в C
GibboK

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

2
@GibboK: ознакомьтесь с этой ссылкой на оператора . И да, в JS есть бинарный оператор AND.
Берги

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

24

Этот ответ очень подробно описывает, как работает в 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к нему
  • «Правда» означает, что выражение может быть оценено как истинное. Вот список правдивых и ложных выражений.

Таким образом, здесь мы смогли избежать дополнительных 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

Это вернет as, что, возможно, сбивает с толку некоторых as 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
Это все еще не дает прямого ответа на заданный вопрос.
Kevin B

7
Это лучший «отличный ответ, который явно не отвечает на вопрос», который я когда-либо видел ...
Херардо Фуртадо

1
Это правильный ответ с подробным объяснением, его следует пометить как принятый и получить гораздо больше голосов, чем сейчас!
Александр Ким
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.