CodeFudge

Delicious snippets of code and logic

JavaScript: Equality !== Truthyness

| Comments

JavaScript, as others, 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 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. 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. false: In boolean context, value evaluates to false.

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.

Calculating falsy/truthy 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.

Few examples of falsy and truthy values
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.

Usage of falsy and truthy values
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
35
36
37
38
39
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.

Equality operator in falsy values - I
1
2
3
4
5
6
0 == ""
>true
false == 0
>true
false == ""
>true

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

Equality operator in falsy values - II
1
2
3
4
null == undefined
>true
null == false
>false

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

Equality operator in falsy values - III
1
2
3
4
NaN == NaN
>false
NaN == false
>false

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

Equality operator: coercion - I
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.

Equality operator: coercion - II
1
2
'string1' == new String('string1')
>true

Please refer to 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.

Strict equality operator
1
2
3
4
5
6
'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.

Caveats: Reference comparison
1
2
3
4
5
6
7
8
9
10
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.

Caveats: Arrays are little messy
1
2
3
4
[] == []
>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.

Caveats: Arrays are little messy
1
2
Boolean(new Boolean(false))
>true

In this case, Boolean is trated 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

Comments