Doing a correct check

Hi, is there any reason why developers write obj.sth && obj.sth.sth ? Like, checking for the existence of an object key/method before chaining on. After all, both will get evaluated - I think. But turns out that it seems if obj.sth is falsy obj.sth.sth does not get evaluated.

I have been seeing it for a while and ignoring it. I am ready to understand now.
Here is what I ran into:

if (ref.current.contains(e.target)) return; // ref.current  was null... understandably, it throws an error 
if (ref.current?.contains(e.target)) return; // I  have been using optional chaining
if (ref.current && ref.current.contains(e.target) return; // baffles me why it throw no error

Thanks in advance.

This is actually pretty important in “real” programs. In JavaScript, we are not guaranteed that the parameter that is passed into a function will match our expectations, so we have to perform input validation.

Let’s say want to greet your cat and I have:

sayHi(person.cat.name);

But, when person is ArielLeslie, you will have a problem, because I do not have a cat. This will cause an error cannot read "name" of undefined. Syntax errors are bad news and can cause your program to stop running.

We could also have a problem if person is Holly Golightly, because

He’s all right! Aren’t you, Cat? Poor Cat! Poor slob! Poor slob without a name! The way I see it I haven’t got the right to give him one. We don’t belong to each other. We just took up one day by the river.

Depending on what sayHi does, we could get a similar ____ does not exist on undefined error, or we could just end up with a logical error where we do something like print “Hello undefined. You are a handsome cat.”

So what’s the solution? Only perform the action if the data is valid

if (person && person.cat && person.cat.name) {
    sayHi(person.cat.name);
}

(This has recently gotten much tidier with optional chaining)

1 Like

Interesting stuff, i pick up. But u didn’t answer my main question.

Thanks for taking your time to answer me!

My main question is why line 3 in the code does not throw cannot read property of contains of null

This line?

Because, if ref.current is null, then the first part of the condition fails and the second part is never checked. :slight_smile:

3 Likes

Looks like it’s short circuiting. I didn’t think of that.

2 Likes

That’s exactly what’s going on. short circuiting ftw

1 Like

There is something called “short circuiting” in logical operators. It will stop performing checks once they become irrelevant. In the case of &&, it will be false if either of the pieces are falsy, so it stops as soon as it encounters a falsy value (like ref.current).

On the flip side, || conditions will be true if either is truthy, so it stops when it encounters a truthy value.

(This is also why it’s important to get the order correct when doing person && person.cat && person.cat.name. It will stop when it hits an undefined).

3 Likes

Which makes beautifully compact code, which can sometimes also be harder to read.

1 Like

Thanks so much everyone! I get now.

1 Like

In JavaScript every variable has an inherent boolean value, generally known as either truthy or falsy. So if you pass just a variable to if statment, it just checks for its “truthy-ness”.

The following values are always falsy :

  • false
  • 0 (zero)
  • '' or "" (empty string)
  • null
  • undefined
  • NaN

Everything else is truthy.

So in the code you posted, in the last line javascript just checks if (ref.current) is a truthy, if it is then after && you can use the variable normally. Because you now know its not a null, undefined or any other falsy value mentioned above.