8

I'm checking the number of digits in a string using the match and length properties. Here is the codepen with my function http://codepen.io/PiotrBerebecki/pen/redMLE

Initially when returning numberOfDigits.length I was getting an error message (Cannot read property 'length' of null). I've solved this issue by changing the line to (numberOfDigits && numberOfDigits.length). This works but I would like to get a better understanding why the new statement can be executed now. Does the interpreter execute the `numberOfDigits.length now?

Also, why are we getting the same errors when the operands are reversed (numberOfDigits.length && numberOfDigits)?

Here is the full JavaScript code:

function checkLength(str) {
  let numberOfDigits = str.match(/\d/g);
  return (numberOfDigits && numberOfDigits.length);
}

console.log(  checkLength('T3xt w1th sOme numb3rs')  );
console.log(  checkLength('Text with some numbers')  );

UPDATE 1: The answers below explained that:

  • The order of the operands in the && expression counts.
  • JavaScript optimises the && operator and if the first operand evaluates to null then JavaScript does not check the second one as the expression cannot evaluate to nothing else than null / false.
Piotr Berebecki
  • 7,428
  • 4
  • 33
  • 42

5 Answers5

6

JavaScript tries to optimise the && operator:

numberOfDigits && numberOfDigits.length

If numberOfDigits is a falsy value (and null is falsy), then the entire expression will be falsy and there is no need to evaluate numberOfDigits.length.

Falsy values are: undefined, null, 0, '', false, NaN. One way to check if something is falsy is to use the Boolean(falsyValue) === false (or more practical but less verbose ! falsyValue).


This is a side effect of the && operator. I can recommend to avoid using it and transform the code to something readable:

function checkLength(str) {
  let numberOfDigits = str.match(/\d/g);
  return Array.isArray(numberOfDigits) ? numberOfDigits.length : 0;
}
Dmitri Pavlutin
  • 18,122
  • 8
  • 37
  • 41
  • Actually, "the entire expression" will be *falsy*, not false. It will be equal to `null`, to be precise. – Hugo Wood Apr 13 '16 at 15:00
  • @HugoWood Good tip. Thanks :) – Dmitri Pavlutin Apr 13 '16 at 15:01
  • 2
    `Boolean(falsyValue) === false` is a rather verbose way to write `!falsyValue`. – user2357112 Apr 13 '16 at 16:46
  • @user2357112 `Boolean(value)` returns `false` for falsy and `true` for truthy, which is easier to understand in terms of learning (instead of `!!value`) – Dmitri Pavlutin Apr 13 '16 at 17:03
  • 2
    @DmitriPavlutin: It might be easier to understand for newbies, but `Boolean(falsyValue) === false` doesn't deserve to be called the "correct way" to do the check. We have too many people thinking comparisons are a different "part of speech" than values and doing things like `if (flag === true) {return true;} else {return false;}`. – user2357112 Apr 13 '16 at 17:12
  • @user2357112 Thanks for noticing. Now reading your comment everyone will have even a better understanding. – Dmitri Pavlutin Apr 13 '16 at 17:15
3

"Does the interpreter execute the `numberOfDigits.length now?"

No, JavaScript short-circuits logical expressions - as soon as result is known (i.e. first operand in and is falsy or first operand in or is truthy), no further operations are executed in the expression.

Docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators

also, beware: && and || do not necessarily return Booleans in JavaScript

Tomasz Lewowski
  • 1,935
  • 21
  • 29
2

the reason is that when the interpreter sees two operations connected with a logical and (&&) it will first execute the former, and only if it is evaluted to true then it will execute the latter.

that is why since it found numberOfDigits to be null, which in JS is equivalent to false, it stops execution and never crashes on numberOfDigits.length.

the other way around will, of course, crash.

on a logical OR (||) the interpreter will stop evaluating after the first statement to be true.

Or Yaniv
  • 571
  • 4
  • 11
1

I believe the reason is that the order of conditions counts.

The numberOfDigits condition gets evaluated first, so if that is false, the rest of the conditions are not evaluated and you won't get an error.

In the other order you would try to read "length" property of null, generating an error.

Th0rndike
  • 3,406
  • 3
  • 22
  • 42
1

"And" logic will be executed as below.

true & true = true  
false & anything = false`

If first condition fails then there is no point of executing second one. so it wont execute numberOfDigits.length if numberOfDigits is null or undefined so no error in the below case.

(numberOfDigits && numberOfDigits.length) => false
     false      && anything               => false

In same way if first condtion is not null then it will execute second condition.

(numberOfDigits && numberOfDigits.length) => true
    true        && true (must be)         => true

Note : In javascript null and undefined are interpreted as false in conditional statements.

kakurala
  • 824
  • 6
  • 15