Published Jan 12, 2017Last updated Jan 18, 2017

How to Avoid Common Pitfalls in JavaScript

How to Avoid Common Pitfalls in JavaScript

JavaScript is a powerful language, but there are certain syntactical and behavioral pitfalls in the language that a newcomer may fall for. These pitfalls generally arise due to properties such as type coercion and evaluation methodology of == & === operator. The == and === operators evaluate an expression using the abstract equality comparison algorithms and the strict equality comparison algorithm (more about it in this tutorial: == vs === JavaScript: Double Equals and Coercion . JavaScript is a weakly typed language. This means that variables can automatically be changed from one type to another while evaluating an expression. Although this is a very powerful feature of the language, it might give rise to some unconventional situations.

Understanding why these behaviors occur

1. Equality of empty arrays

> [] == []

On first look, it sounds ridiculous. An empty array is not equal to itself? But this is not what the above statement actually means. Arrays are stored by references in JavaScript and in JavaScript, the double equal operator returns true only when you're comparing the same instances of the same type. The comparison above actually asks, "Is an instance of empty array equal to an instance of another empty array?" which is definitely false. The statement above is similar to:

> var a = [];
> var b = [];
> a == b

a and b are references to two different locations in memory, hence the result is false. However, if both the array instances have been same (like the one below), then the answer below would have been true.

> var a = b = [];
> a == b

2. Equality of an empty array and NOT empty array

> [] == ![]

Before understanding what is happening above, we need to understand the concept of truthy and falsy in JavaScript and how the ! (logical NOT) operator works. Values such as false, null, undefined, NaN, 0, '' and "" are considered as falsy. Other values like true, {}, [], "foo" etc. are considered truthy. The ! operator, on the other hand, is defined for boolean values only. Any other data type will automatically be coerced into it's corresponding boolean value when operated with ! operator. Here, ![] evaluates to false and the comparison actually becomes:

> [] == false

Isn't that supposed to be false, since empty arrays are truthy? That's right but the double equal operator evaluates expressions on certain rules. We're trying to compare an object with a boolean value and JavaScript will implicitly convert the operands to Number type. Number([]) is 0 and Number(false) is also 0, which evaluates to true since zero is equal to zero.

3. Empty array plus empty array

> [] + []

It might look like the sum of two arrays will concatenate them and hence, on adding two empty arrays, one might get another empty array. But that's not the case in JavaScript. As stated in the ECMA language specification, the addition operator either performs string concatenation or numeric addition. Hence, the + is not defined for arrays and JavaScript will implicitly convert arrays into their string equivalent and concatenate them. The above expression will become similar to:

> [].toString() + [].toString()

Concatenate of two empty strings yields another empty string and hence the above statement is valid.

4. Empty array minus empty array

> [] - []

This case is similar to the previous one. The - operator is not defined for arrays or strings. Hence, JavaScript will implicitly convert the arrays into their corresponding number type. Coercion of empty array into number type yields 0. The above expression is the same as:

> Number([]) - Number([])

Zero minus zero is obviously zero, which makes sense.

5. Weird array equal weird string

> [null, undefined, []] == ",,"

This is quite weird. When we try to compare a non-empty array with a string, Javascript coerces each array element into a string and then joins them by commas. Stringification of null, undefined & [] gives an empty string. Hence, the expression [null, undefined, []].toString() yields ",,".

6. Plus empty array

> + []

That's actually not WAT. In Javascript, the unary plus operator is used to explicitly convert the object into a number type. So the above statement is similar to:

> Number([])

7. Empty array plus empty object

> [] + {} 
"[object Object]"

You might have guessed this one. As seen in on the third item, JavaScript will coerce the array and the object into string and then concatenate them. The default conversion for an object type to string is [object type], where type is the type of object. There are different types of objects in JavaScript like Object, Function, Array, RegExp etc. In this case it's Object.

> "" + "[object Object]"
"[object Object]"

8. Empty object plus empty array

> {} + []

Wait! Didn't we just say that JavaScript coerces object and array to string on plus operator? This is actually a bizarre edge case of JavaScript. The JavaScript compiler understands this statement a bit differently. It considers {} as an empty code block and + [] as another statement. We saw + [] equates to 0 which is why the above expression evaluates to 0.

9. Empty object plus empty object

> {} + {}

This one is similar to the example above. Explicit conversion of an empty object into number type yields NaN.

10. The null and zero

> 0 < null
> 0 >= null 
> 0 == null 

Well, that's frustrating. JavaScript double equal operator and the relational operator are based on the abstract equality comparison algorithm and the abstract relational comparison algorithm. It's just a fancy set of rules to evaluate an expression.

When we compare 0 and null using relational operators, JavaScript coerces null into its primitive number type. When using relational operators the comparison is similar to

> 0 < Number(null)
> 0 >= Number(null)

null when converted to number type yields 0 which explains evaluation of the above statements. However, with the == operator, such a comparison doesn't fall into any category of rules defined for evaluation of expression by == operator. Neither 0 nor null gets coerced and by rule, if such a case occurs, where the comparison doesn't fall into any category, false is returned.

11. Math.min is greater than Math.max

> Math.min() > Math.max()

A lot of programming languages define global maximum and minimum values and so does JavaScript, but not with Math.max() or Math.min(). They are, instead, used to return maximum and minimum values within a group of numbers.

When these functions are called without arguments, Math.max() returns Infinity and Math.max() returns -Infinity.

> Math.min(1, 2, 3, 4)
> Math.max(1, 2, 3, 4)

JavaScript employes Number.MAX_VALUE and Number.MIN_VALUE for this task and they work as expected.

> Number.MIN_VALUE < Number.MAX_VALUE

Wrapping up

That's it! If you have anything to add feel free to comment below. You can also check out this handa JavaScript Cheat Sheet to know more about JS.

How to Effectively Develop Vanilla Javascript Application
Localizing time in a Traditional Rails app with Moment.js
JavaScript Best Practices: Tips & Tricks to Level Up Your Code