JavaScript, as others languages, have branching statements. These branching statements decide the flow of execution when provided with few specific conditions[i.e. stimulus]. These conditions are Boolean in nature. Besides default Boolean variables and equality operators, each DataType in JS has a Boolean[Truthy/Falsy] associated with it. In addition to these, equality operator are also of two type, strict equality operator and Coersion based equality operator. Understanding each of these can save a lot of pain while writing complex JS code.

Mission of This Tutorial #

Main Problem: #

To understand how JS equality operators and truthy/falsy values can be used to advantage.

This problem statement can be divided into multiple parts:

  • Understand how variables/objects act as truthy/falsy values.
  • Understand Coercion based abstract equality operator.
  • Understand Strict equality operator.
  • know few caveats in the operator
  • Explore some techniques used by folks for equality operations.

Getting Started #

Being an Object Oriented language javascript has few types of objects which can be structured as,

  • Number
  • String
  • Boolean
  • Object

  • Function

  • Array
  • Date
  • RegExp

  • Null

  • Undefined
    All these objects have a boolean value associated with them. These boolean values change with the change in state of given object. For example, if the number is 0 it’s boolean value is falsy where as if number is anything else than 0 it is truthy. This truthyness or falsyness of values also impact equality operators.

Truthyness/Falsyness of Objects #

What exactly is Truthy/Falsy values

When a value is being called truthy, it doesn’t necessarily mean that it is true. It means, it is going to result[coerce] to true when evaluated in boolean context.

Truthy: #

In boolean context, value evaluates to true.

falsy: #

In boolean context, value evaluates to true.

To check whether a value of Object is truthy or falsy, console of any browser can be used. Boolean() can be used to deduce the nature of the value.

1
2
3
4
Boolean("")
> false
Boolean("Hey")
>true

false, NaN, undefined, null, ""[literal form], 0 are always falsy leaving all others as truthy which includes [], {} and empty functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Boolean(false)
>false
Boolean("")
>false
Boolean(NaN)
>false
Boolean(undefined)
>false
Boolean(null)
>false
Boolean("")
>false
Boolean(0)
>false
Boolean("0")
>true

Usage #

These truthy values can be checked in branching statements.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var ann = {
name: 'ann',
age: 10,
preferences: null
}
var john = {
name: 'john',
age: 11,
preferences: undefined
}
var peter = {
name: 'peter',
age: 11,
preferences: ['photography']
}
var tony = {
name: 'tony',
age: 13,
preferences: ['science', 'tech', 'cars']
}
function getPreferences(user) {
if (user.preferences) {
console.log(user.name + " is interested in " + user.preferences.join());
} else {
console.log(user.name + " is not interested in anything that you have to offer");
}
}
getPreferences(tony);
getPreferences(john);
getPreferences(peter);
getPreferences(ann);

This code will work even when preferences is set to 0 or "" or any other falsy value. But when these falsy values have different meanings in the code, then this approach will fail. Also truthiness is not same as being ==true. So any such comparison could lead to unexpected application behavior. For example, [] == true is false even when [] is true.

Abstract Equality Operator #

Any variable, even a function, can be easily compared in JavaScript. This is all simple as long as variables of same type are being compared. But when variables of different types are compared, things start to become weird. When the types are different javascript coerces these values to make them comparable with each other. Comparison of the falsy value among each other itself is little odd and confusing. In case of comparison between primitive and object operands, object is converted to primitive type if possible.

0, "", false are all equivalent and can be compared directly.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Boolean([])
>true
Boolean([]==true)
>false
Boolean([]==false)
>true
0 == ""
>true
false == 0
>true
false == ""
>true

null and undefined do not play with other fellows well but are good to each other.

1
2
3
4
5
null == undefined
>true
null == false
>false

Where as NaN is not equivalent to anything, including NaN itself.

1
2
3
4
5
NaN == NaN
>false
NaN == false
>false

This operator also performs type conversion when a string and a number is compared.

1
2
11 == '11'
>true

When an object is compared with primitive type then, object is converted to primitive type and then comparison is carried out.

1
2
'string1' == new String('string1')
>true

Please refer to The The Abstract Equality Comparison Algorithm#sec-11.9.3 which explains the abstract equality AKA coercion based equality operator.

Please note, this equality operator is not transitive.

Strict Equality Operator #

One can easily get around coercion by use of strict equality operator [=== and !==]. This operator ensures that operands are of same type and have equivalent values. Javascript does not perform coercion when this operator is used.

1
2
3
4
5
6
7
8
'string1' === new String('string1')
>false
11 === '11'
>false
null === undefined
>false

Caveats #

Javascript is famous for it’s equality related caveats. There are few things one must keep in mind while applying various boolean operations on the variables.

Equality comparison algorithm is kind of shallow check based on references for equality in case of object-object comparison. When two objects are compared, the last resort to evaluate whether they are equal or not is to check if they refer the same object or not. It gives rise to following conditions.

1
2
3
4
5
6
7
8
9
10
11
12
13
new Number(1) == new Number(1)
>false
new String("hello") == new String("hello")
>false
"hello" == new String("hello")
>true
new Number(0) == 0
>true
0 == new String("0")
>true

In case of arrays, things are little messy.

1
2
3
4
5
[] == []
>false
![] == []
>true

This behavior is not that strange. In the first case, both the arrays have different references and hence output is false. Whereas in second case, first ![] is executed. It results in false. Then as per Abstract Equality algorithm, [] is coerced to "" or 0 which is also falsy in nature. So ![] == [] results in true.

1
2
Boolean(new Boolean(false))
>true

In this case, Boolean is treated as object and truthyness is calculated.

Widely Used techniques #

To get the truthy value in the comparison one can use double negation before variable reference. !!a returns truthy/falsy value.

It is also useful to use Abstract euqality operator when none of the falsy value has any meaning in the code logic, they are just plain false for your snippet. Otherwise, always apply strict check. Objects comparison must be carried out in a deep check manner as normal comparator limits itself to shallow check based on reference.

References #

ToBoolean - http://www.ecma-international.org/ecma-262/5.1/#sec-9.2

ToNumber - http://www.ecma-international.org/ecma-262/5.1/#sec-9.3

ToPrimitive - http://www.ecma-international.org/ecma-262/5.1/#sec-9.1

Strict Equality comparison - http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.6

Abstract Equality comparison - http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3