Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does JavaScript have "Short-circuit" evaluation?

I would like to know if JavaScript has "short-circuit" evaluation like && Operator in C#. If not, I would like to know if there is a workaround that makes sense to adopt.

like image 670
GibboK Avatar asked Oct 02 '22 06:10

GibboK


People also ask

Does JavaScript have lazy evaluation?

One of the reasons often cited is lazy evaluation. Javascript has the fame of being functional, but it lacks a native way to do most of the stuff commonly considered as such. Again, one of those is lazy evaluation.

Does Python have short circuit evaluation?

The Python or operator is short-circuiting When evaluating an expression that involves the or operator, Python can sometimes determine the result without evaluating all the operands. This is called short-circuit evaluation or lazy evaluation. If x is truthy, then the or operator returns x . Otherwise, it returns y .

Which type of operators use short circuit evaluation?

The logical AND operator performs short-circuit evaluation: if the left-hand operand is false, the right-hand expression is not evaluated. The logical OR operator also performs short-circuit evaluation: if the left-hand operand is true, the right-hand expression is not evaluated.

What is short circuit evaluation in programming?

Short-circuit evaluation, minimal evaluation, or McCarthy evaluation (after John McCarthy) is the semantics of some Boolean operators in some programming languages in which the second argument is executed or evaluated only if the first argument does not suffice to determine the value of the expression: when the first ...


2 Answers

Yes, JavaScript has "short-circuit" evaluation.

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

Live DEMO

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

Live DEMO

like image 154
gdoron is supporting Monica Avatar answered Oct 17 '22 17:10

gdoron is supporting Monica


This answer goes into great detail on how short-circuiting works in JavaScript, with all the gotcha's and also relevant themes such as operator precedence, if you're looking for a quick definition and already understand how short-circuiting works, I'd recommending checking other answers.


What we (thought we) knew so far:

First let's inspect the behaviour we are all familiar with, inside the if() block, where we use && to check whether the two things are true:

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

Now, your first instinct is probably to say: 'Ah yes, quite simple, the code executes the statement if both expr1 and expr2 are evaluated as true'

Well, yes and no. You are technically correct, that is the behaviour you described, but that's not exactly how the code is evaluated and we'll need to delve deeper in order to fully understand.


How exactly is the && and || interpreted?:

It's time to look "under the hood of the javascript engine". Let's consider this practical example:

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

Well the result is 260.. but why? In order to get the answer, we need to understand how does the short-circuit evaluation work.

By the MDN Definition the && operator in expr1 && expr2 is executed followingly:

If expr1 can be converted to true, returns expr2; else, returns expr1.

So this means, in our practical example, the const res is evaluated the following way:

  1. Invoking expr1 - sanitise(0xFF)
  2. 0xFF is a valid hexadecimal number for 250, otherwise I'd return NaN
  3. The expr1 returned a "truthy" value, time to execute expr2 (otherwise I'd stop as NaN is falsy)
  4. Since userinput is truthy (a number), I can add +5 to it
  • "Truthy" means that expression can be evaluated as true. Here's a list of truthy and falsy expressions.

So here, we were able to avoid additional if blocks and further isNaN checks with a simple usage of the && operator.


How it really works:

By now, we should at least have a picture how the short-circuit operators work. The universal rule goes:

  • (some falsy expression) && expr will evaluate to falsy expression
  • (some truthy expression) || expr will evaluate to truthy expression

Here are some further examples for better comprehension:

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

One last pesky, but very important thing [Operator Precedence]:

Nice, hopefully you're getting the hang of it! Last thing we need to know is a rule about operator precedence, that is:

  • The && operator is always executed prior to the || operator.

Consider the following example:

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

This will return as, perhaps confusingly to some as a(). Reason is quite simple, it's just our eye-sight that's kind of deceiving us, because we're used to reading left-to-right. Let's take the console.log() and what not out and focus purely on the evaluation

true || false && false

Now to wrap your head around this:

  1. We said the && operator has precedence, so it gets evaluated as first. To help us better imagine the evaluation, think of the definition

    expr1 && expr2
    

    Where:

    • expr2 is false
    • expr1 is true || false
  2. So that was the tricky part, now true || false is evaluated (the expr1 - left-side of the &&).

    • Given the || operator stops execution if expr1 || expr2 in expr1 evaluates as truthy, the expr1 is executed and code execution stops.
  3. The returned value is true

Well.. that was pretty tricky, all because of few weird rules and semantics. But remember, you can always escape operator precedence with the () - just like in math

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()  
*/
like image 50
Samuel Hulla Avatar answered Oct 17 '22 15:10

Samuel Hulla