Abstract Operations—the key to understand Coercion in JavaScript
Tags: javascript, webdev, productivity, codequality
Published: 2019-08-27 14:02:40

I was intrigued by one the question asked on my [**So you think you know JavaScript**](https://dev.to/aman_singh/so-you-think-you-know-javascript-5c26) article.

```js
 {} + []; // returns 0 ?? 🤔
``` 
I admit that I didn't know the correct answer at that moment, but instead of blaming and criticising the JavaScript coercion and type system, I delved into the specs to find the definition of [**Addition operator**](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus). At first, the specs didn’t make much sense to me. I found it verbose. May be my brain wasn't trained on reading the specs. Yeah, let's be honest, how many of us read the specs when there's a question about JavaScript? We have our beloved *StackOverflow*. Right? 

Well, I was desperate to know the answer. I didn't want to be in the category of those devs who consider coercion as some internal magic and dangerous, to be shunned or avoided. 

So, this article is to share my understanding of **coercion** in JavaScript, and illustrate why coercion's bad reputation is exaggerated and somewhat undeserved—to flip your perspective so you can see its usefulness and power.

## JavaScript Type System
JavaScript is a **dynamically typed** language where variables don't have types—**values have types**. JavaScript type system doesn't enforce that the variable always holds the same initial type it starts out with. 

```js
  // variable 'a' starts out with holding a string value type. 
  var a = 'some string'; 
  
  // you can change the type in the next line and it's completely valid
  // Now, the variable 'a' holds the value of type number
  a = 10;
```

I always see this as one of the strongest points of the JavaScript type system. But some devs from strongly typed language may find this as a flaw in the language and object the usage of word 'type'. And I think that's one of the many reasons we are perpetually exploring the ways ([Flow](https://flow.org/en/) and [TypeScript](https://www.typescriptlang.org/)) to put a layer of type system on the language. In my opinion, it's like we are duck-taping JavaScript into a system which is **not** in the DNA of the language. 

I believe we should always strive to learn the fundamentals and think alike JavaScript. Instead of flowing against it, let's flow towards it and see why the aforementioned question shouldn't be overhyped thinking that JavaScript is weird. 

Let's quickly revisit what we know so far about **JavaScript types** and then we will deep dive into **coercion** in the later sections. 

JavaScript has seven built-in types: 
- null
- undefined.
- string
- number
- boolean
- object
- symbol
 
Except **object**, all other types are called 'Primitives'. **[typeof](https://www.ecma-international.org/ecma-262/#sec-typeof-operator)** operator is a nice built-in utility to check the types. Keep in mind that _typeof_ always returns a **string** type. 

```js
typeof 'you are awesome!' // 'string'
typeof 42                 // 'number'
typeof true               // 'boolean'
typeof undefined          // 'undefined'
typeof {name: 'aman'}.    // 'object'
typeof Symbol()           // 'symbol'

------------------------
typeof function foo(){}.  // 'function'
typeof []                 // 'object'
```

You will be wondering why invoking _typeof_ on **function** and **array** return 'function' and 'object' respectively. The reason is that _functions_ and _array_ are subtypes of the _object_ type. And because of this, you are able to add properties to the function and invoke some of the methods which an object type has—**[toString()](https://www.ecma-international.org/ecma-262/#sec-object.prototype.tostring)**, and **[valueOf()](https://www.ecma-international.org/ecma-262/#sec-object.prototype.valueof)**. 

```js
function foo(a,b){}

// you can add any property on foo object. 
foo.someProperty = 'I am a property on foo function'; 

// function object has 'length' property set to number of formal params it takes when declared
foo.length; // 2

// invoke 'toString()' 
foo.toString(); // "function foo(a,b){}"

// invoke 'valueOf'
foo.valueOf(); // return this -> the function itself 
```

> **Bonus**: According to the [_typeof_](https://www.ecma-international.org/ecma-262/#sec-typeof-operator) spec, if an object type implements an internal [[[Call]]](https://www.ecma-international.org/ecma-262/#sec-ecmascript-function-objects-call-thisargument-argumentslist) method, then _typeof_ check returns "function". Object literals and array don't implement it, but the function does. 

There are a few gotchas you need to be aware of with _typeof_ operator. As you may have noticed that I have excluded _typeof null_ from the list above. The reason is that **null** is a special case where _typeof_ operator returns 'object'. It's the only primitive in JavaScript which is 'falsy' and returns 'object' from _typeof_ check. 

> **Note**: _null_ is the only primitive in JavaScript which is '**falsy**' and returns an ’**object**' from **typeof** check. 

```js
typeof null; // 'object'; 
```

So, how would you go about checking the _null_ type explicitly? You may need a statement like: 
```js
var a = null; 
!a && typeof a == 'object'; // true

// Or you can use strict equality comparison
a === null; // true
```

Let's consider one more quirk with typeof operator:
```js
var a; 
typeof a; // 'undefined'
typeof b; // 'undefined'
```
In JavaScript, **var declared** variables get assigned a value of **undefined** when they have no current value. And that's the reason _typeof_ operator returns '**undefined**'. But if you see we haven't declared the variable **b** anywhere, but _typeof_ operator still manages to print 'undefined'. It's because JavaScript engine is playing safe and instead of returning some error, it returns undefined. 

As I said knowing these difference is like aligning your mind with JavaScript engine. Every language has some corner cases. JavaScript is not an exception. Instead of making a joke about the language, I think it's crucial to understand them so that you can take better decisions in your program. 

Now, let's move on to the next part of understanding coercion in JavaScript.  

## Coercion
Coercion aka 'type conversion' is a mechanism of converting one type to another. In statically (strongly) typed language this process happens at compile time whereas coercion is a run-time conversion for dynamically typed languages. 

In JavaScript, we can have two types of coercion: "implicit" and "explicit". As the name implies, **implicit** coercion is the one which happens as a **less obvious** side effect of some intentional operation. On the contrary, the **explicit** conversion is obvious from the code that it is occurring intentionally. 

```js
var a = 10; 

var b = 'programmer' + a;           // implicit coercion
var c = `you owe me ${a} dollars`.  // implicit coercion

var d = String(a);                  // explicit coercion
var e = Number('42')                // explicit coercion 
```

Have you ever wonder how coercion works internally? That's where things get interesting. But before we can explore the internal procedures, we need to understand some of the operations which are defined in ECMAScript 2020 section 7 called **[Abstract operation](https://tc39.es/ecma262/#sec-abstract-operations)**. These operations are not part of the language but are used to aid the specification of the semantics of JavaScript language. You can think of these operations as conceptual operations. 

### Abstract Operations
Every time a value conversion happens, it is handled by one or more abstract operation with some rules defined in the spec. Here we will look into three abstract operations: **ToString**, **ToNumber** and **ToPrimitive**. 

> Abstract operations are used to aid the specification of the semantics of JavaScript language.

#### ToString
Whenever we coerce a non-string value to a string value, **ToString** handles the conversion as in [section 7.1.12](https://tc39.es/ecma262/#sec-tostring) of the specification. Primitive types have natural stringification. The table looks like: 

```js
// ToString abstract operation (string conversion)
null ->            'null'
undefined ->       'undefined'
true ->            'true'
false ->           'false'
52 ->              '52'
```

For regular _object_ and _array_, the default _toString()_ is invoked which is defined on the [Object.prototype](https://www.ecma-international.org/ecma-262/#sec-object.prototype.tostring) 

```js
var a = {language: 'JavaScript'}; 
a.toString(); // "[object Object]"

[].toString(); // ""
```

 You can also specify your own _toString_ method to override the default return value: 

```js
var a = { language: 'JavaScript', toString(){return 'I love JavaScript'} }; 

a.toString(); // "I love JavaScript"
```

#### ToNumber
Whenever a non-number value is supplied in an operation where a number was expected, such as a mathematical operation, ES2020 defines a **ToNumber** abstract operation in [section 7.1.3](https://tc39.es/ecma262/#sec-tonumber). For example 

```js
// ToNumber abstract operation (number conversion)
true ->           1
false ->          0
undefined ->      NaN (not a valid number)
null ->           0 
```

For _object_ and _array_, values are first converted to their **primitive value** equivalent (via [ToPrimitive](#toprimitive) operation) and the resulting value is then coerced into number according to the **ToNumber** abstract operation. 


#### ToBoolean
**ToBoolean** is a little simpler than **ToString** and **ToNumber** operation as it doesn't do any internal conversion. It only performs a table lookup as mentioned in [section 7.1.2](https://tc39.es/ecma262/#sec-toboolean). 

Argument type | Result
--- | ---
undefined | **false**
null | **false**
boolean | return **argument**
number | if argument is +0, -0 or NaN, return **false**; otherwise **true**
string | if argument is empty string, return **false**; otherwise **true**
symbol | **true**
object | **true**


#### ToPrimitive
If we have non-primitive type (like function, object, array) and we need a primitive equivalent, ES2020 defines **ToPrimitive** in [section 7.1.1](https://tc39.es/ecma262/#sec-toprimitive).

**ToPrimitve** operation takes two arguments: input and **hint**(optional). If you are performing a numeric operation, the hint will be a 'number' type. And for string operation (like concatenation), the hint passed will be a string. Note that ToPrimitive is a recursive operation which means that if the result of invoking ToPrimitive is not a primitive, it will invoke again until we can get a primitive value or an error in some cases. 

Now let's look at the algorithm behind the ToPrimitive operations. 

Every non-primitive can have two methods available: **toString** and **valueOf**. If 'number' hint is sent, **valueOf()** method is invoked first. And if we get a **primitive type** from the result then we are done. But if the result is again a non-primitive, **toString()** gets invoked. Similarly, in the case of 'string' hint type, the order of these operations is reversed. If the invocation of these two operations doesn't return a primitive, generally it's a **TypeError**. 

Visually, The order can be seen as follows: 

```js
// ToPrimitive Abstract Operation

// hint: "number" 
valueOf()
toString()

// hint: "string"
toString()
valueOf()
```

To make it more clear here's the flow chart diagram of the algorithm we discussed above: 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/skc2q8wj2t4zb6hovu5r.png)

Now armed with this new knowledge of abstract operations, it’s the time to answer a few questions confidently. 

## Testing our knowledge
```js
// Why the following expression produces '5' as a result? 
[] + 5; // '5'
```

As per the specification in section, the [addition operator](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus)  ‘+’ performs string concatenation or numeric addition based on the argument type. If either of the argument is string, it will perform string concatenation. It's called [operator overloading](https://en.wikipedia.org/wiki/Operator_overloading). Now let see how did we end up getting the string **”5”**?

We were expecting a **primitive type** but end up getting an _array_ as one of the argument. Consequently, **ToPrimitive** abstract operation is performed with **"number"** passed as a hint. Referring to the ToPrimitive diagram above, we can assert the following steps will take place to get the result. 

- [].**valueOf()** // returns []; 
- As, [] is **not** a primitive,  engine will invoke [].**toString()** resulting in an **empty** string. 
- Now the expression reduces to **"" + 5**.
- As we mentioned that *addition operator performs string concatenation* when either of **argument** is a **string type**. 
- So, 5 will be implicitly coerced to **“5”** via **ToString** abstract operation passing **'string'** as a hint. 
- Finally the expression reduces to **"" + "5"** resulting in value **"5"**. 

```js
[] + 5;               // ToPrimitive is invoked on []
// "" + 5; 
// "" + "5"; 
// "5"
```

Now, that's a moment of inner satisfaction. Isn't it? I don't know about you but when I figured this out, I was delighted💡😀.  

Before we wrap up, let's quickly demystify some of the following expression to strengthen our grip. I am going to reduce the expression from top to bottom (via abstract operations) to reach the result. 

```js
[] + [];            // ToPrimitive is invoked on both operands
// "" + "";
"" 
-----
[] + {};              // ToPrimitive is invoked on both operands
// "" + "[object Object]";
"[object Object]"

-----
'' - true; 
// There's no operator overloading for subtract operator. 
//ToNumber is invoked on both the operands (already primitive)
// 0 - 1; 
-1

------
1 < 2 < 3; 
// (1 < 2) < 3;      
// true < 3;              // ToNumber is invoked on true -> 1
// 1 < 3;
true; 

------
3 < 2 < 1; // true ooops! 
// (3 < 2) < 1; 
// false < 1;             // ToNumber is invoked on false -> 0
// 0 < 1; 
true
```


Now is the right time to answer the question which basically led me to write this article. 

```js
{} + []; // 0 🤔??
```
Here '{}' is **not an empty object** but just an empty block {}. So, JavaScript engine ignores it and left with `+ []` statement to execute.  It’s a *numeric operation* and hence a *‘number’* hint will be passed to convert this empty array into a *primitive* value, which is an *empty string*.  Finally, the empty string is coerced again via **ToNumber** operation leading to a value of **0**. 😀

```js
{} + [];                 // empty block is ignored
// + [];
// + '';
// + 0 ;
0
```

## Summary: 
- JavaScript is a dynamically typed language where **values have type**—not the variables. 
- **[Coercion](#coercion)** aka “type conversion”  is a procedure of converting one value type to another; it happens at compile time for JavaScript. 
- Coercion can be of two types: **implicit** and **explicit**. 
- **[Abstract operations](#abstract-operations)** are the keys to understanding coercion. They are not actual operation in the language but are used to aid the specification of the semantics of JavaScript language. 
- Whenever we receive a non-primitive value for an operation where a primitive type was expected, **[ToPrimitive](#toprimitive)** abstract operation is invoked. 
- For any non-primitive, ToPrimitive invokes two methods: **valueOf()** and **toString()**. Depending upon the **hint** passed, **valueOf()** followed by **toString()** is invoked for the ‘number’ hint , and vice versa for “string”. 

## Conclusion: 
Dynamic nature of JavaScript is one of its core features. Understanding how coercion works internally can help us write robust code. Every language has some quirks and it’s our responsibility as a developer to be mindful of these caveats. Instead of finding flaws, we need to strive for learning the semantics of the language and work towards it.   

Hope you liked the article and if that’s a _boolean_ **true**, a few ❤️ will make me smile 😍.