(Be advised: Names and code has been changed to protect the guilty).
We all like default values assigned when a value is not supplied. In the past, I setup my code like this:
class myClass {
constructor (params) {
this.aString = params.aString || null;
this.aNumber = params.aNumber || null;
this.anotherString = params.anotherString || null;
// yada, yada, yada
}
}
In the past, this always worked well. I mean, I found it on the Internet. You can trust anything there. In this case, I always set a value to null to signify that the parameter wasn’t set. It’s up to the code base to deal with it correctly.
Until I got a call.
“Hey, TheVirtuoid”. It was the CEO of the company. “We’ve got a problem.”
I never have problems. What ever it was, it was his fault.
“We’re trying to put a number into our transaction, and it keeps telling us that the transaction is invalid. What gives?”
The dude makes a billion dollars a year, so I’m certain it’s his fault. Numbers are across the top of the keyboard, not in the middle, my man. I took a deep breath. “I’ll look into the logs and get back to you” I said.
I looked in the logs, knowing full well that I would find nothing.
TypeError: Cannot read property "toString" of null
“HOLY EXCEPTION, BATMAN!” I screamed. There WAS an error. The was an error in my PERFECT code!
I looked back in the logs to find the variable in question. It was the “aNumber” property of the class. He had entered the number Zero. No, not the text “Zero”, but the actual number “0”.
“That’s impossible” I mumbled. Of course it’s impossible. My code is perfect. Obviously, some doofus at Google purposefully change the JavaScript engine inside Chrome just to make my code fail.
I traced the error to the validateTransaction method. Someone made changes to it last week. “There’s another doofus for you” I thought. Some punk junior developer fresh out of grammar school has completely torn up this class. I guess I need to swoop in and save the day.
And yet, looking at the code, it should have worked.
I leaned back in my chair, deep in thought. Someone else has messed up my code…
…and then I got that deep, sinking feeling in my stomach. I realized what happened, and that someone was me.
You see, the problem is how JavaScript interprets the Logical OR operator. Let’s look at the code again:
this.aNumber = params.aNumber || null;
In a Logical OR, each expression is tested left to right until a “truthy” expression is found, and that expression will be used. If all the expressions are “falsey”, then the final expression is returned.
The key here is “truthy” and “falsey”. Notice I didn’t say “true” or “false”. In JavaScript, “truthy” and “falsey” are values that are considered to be Logical True or Logical False. We all know about Boolean True and Boolean False – there are two settings and that’s it. But a Logical True and a Logical False expands this concept to include certain values. In JavaScript, there are eight values that are considered “falsey”. They are:
- Boolean False
- The Number Zero
- The Number Negative Zero
- The BigInt Number Zero
- And Empty String
- null
- undefined
- NaN
(source: MDN docs)
Now, the logs said that the CEO typed in the number 0. So given this code:
this.aNumber = params.aNumber || null
“params.aNumber” was equal to 0, which in JavaScript, is a “falsey” value. Therefore, with the first expression “falsey”, the second expression, null, was returned. And, of course, there is no “toString()” method on null, which caused the exception.
How do we fix it?
Use the Ternary operator!
this.aNumber = params.aNumber !== undefined ? params.aNumber : null;
Now I check to see if the number is not undefined. If that succeeds (which means the parameter is there), then we use the value of params.aNumber. Otherwise, we use null.
Problem solved. My code is perfect again.
I’ve been using the first method for over a hundred years without problems. In fact, if you google how to setup default values in JavaScript, you’ll see the Logical OR example all over the place. And, for the most part, it works well.
But it can get you.
Bottom line: Use Ternary operators.
See you later!
Categories: Javascript
thevirtuoid
Web Tinkerer. No, not like Tinkerbell.
Creator of the game Virtuoid. Boring JavaScript. Visit us at thevirtuoid.com
Leave a Reply