Introduction
Recently I took a Salesforce JavaScript exam and I thought, I've been working with JavaScript or over 10 years, this should be easy. Well it was not. It Made me realise how much I had overlooked within JavaScript. How some code I could be writing every day, but what is actually happening in that line of code?
I found some of the quirks of JavaScript so fascinating that I went and asked some expect JavaScript developers some of these questions, and surprise surprise, most of the them got them wrong. Here I will walk you thought a few of these findings. If you don't believe the code, feel free to open your browser console and execute the code for yourself.
Implicit and Explicit Type Conversion
There are 2 types of type conversions: explicit, where you go and manually convert from one type to another, e.g.
parseInt('123');
Then there is implicit where the type is automatically converted, e.g.
15 - '2' //13
In the above example, the string '2' is automatically converted into a integer and the result would be 13. This is true for all mathematical operations apart from when using the + symbol. Here, instead of implicitly converting the string to a number, the number will be converted into a string and they'll both be concatenated. E.g.
'15' + 2 //'152'
Now what if we tried adding (or other mathematical operations) a Boolean to a number? Well, the Boolean would be implicity converted to a number and a value of 'false' would evaluate to 0 and a 'true' value would evaluate to 1. E.g.
15 + true //16 15 + false //15
Okay, that's enough examples. Let's look at some comprehensive description of these rules:
LOOSE EQUALITY OPERATOR
The loose equality operator (== or !=)is used to determine if two operands are equal or not. It coerces primitives to numbers except for null and undefined (null only loosely equals to null and undefined)
So if you ever use the == or != operators, primitives such as strings and Booleans will be coerced into numbers (implcity converted) and that's how they will be compared, where null and undefined are the exceptions. E.g.
null == undefined // true Number(null) == Number(undefined) // false
COMPARISON OPERATORS
A comparison operator (>=, >, <=, or <)are used to determine if one value is greater than, less than, or equal to the other value. It coerces primitives to numbers.
Similarly, using > style operators will coerce primitives to numbers.
LOGICAL OPERATORS
OR (||), AND (&&), and NOT (!) are logical operators used to determine if an expression evaluates to true or false. They coerce primitives to boolean.
Now using logical operators such as && will actually coerce primitives to Booleans.
E.g. you might want to test if one of your string has a value:
'a' && 'b' // 'a' 'a' && '' //'' '0' && '1' // '1'
The above example will be evaluated as true, even though we have a 0 but because it is a string, it is treated as true.
ARITHMETIC OPERATORS
Arithmetic operators (-, +, /, and *)are used to subtract, add, divide, ormultiply values. They coerce primitives to numbers,except when + is used, if one operand is a string, the result is a string.
This is similar to the original examples we looked at the beginning of the section.
true – 1 // 0
True is coerced to a number to 1 and minus 1, you have 0.
Things that will catch you out:
Look out for the following, these are where people are really caught out:
NaN == NaN //false Number('abc') == NaN //false
NaN is never equal to anything. If you need to check if a value is not a number, you need to use :
Number.isNaN(NaN) // true
Empty objects and empty arrays are coerced to true, even if they are empty:
Boolean({}) // true Boolean([]) // true
When coercing an object to a number, the valueOf() function is called on the object. So you could do the following:
var objOne = { valueOf() { return 123 }} objOne == 123 // true Number(objOne) // 123
If the valueOf() function returns a primitive, it will be used, else the toString() function will be called:
var objOne = { valueOf() { return {} }, toString() { return 123 }} Number(objOne) // 123
The toString() method will always be called first though if you are converting to a date:
var objOne = { valueOf() { return Date.now() - 10000 }, toString() { return Date.now }} Date(objOne) // 'Fri Dec 24 2021 12:25:21 GMT+0000 (Greenwich Mean Time)'
But doing the following:
{} == {} // false
This is because even though the objects look the same, they both have references to different objects. To compare 2 objects, you could use JSON.Stringify():
JSON.stringify({}) == JSON.stringify({}) // true
Just remember though that functions on the objects won’t be stringified.
Happy coding!
Comments