Coercion: Deep Dive
Tags: javascript, coercion
Published: 2019-11-23 16:11:46


From the beginning of history of `Javascript`, developers thought that `coercion` is evil and confusing and start to ran away from it. First, let's see what's coercion really.

### Definition

**Coercion:** it's the conversion from data type into another in javascript. It's called in other programming languages `Type Casting`. There's a lot of arguments around this definition, but what I liked is that (`Type Casting`) is the conversion in statically typed languages like _Java & C++_, while (`coercion`) is the conversion in dynamically typed languages like _Javascript_.

### Types

**Explicit Coercion**

It's the conversion from type into another by intention. like:

```javascript
String(23); // "23"
```

Here we converted the number 23 into string "23" by explicitly calling `String()` constructor. This process is very similar to _Type casting_ in java as we do:

```
int(23)
```

The `String()` constructor uses what's called **Abstract operations** which defined in the `specification` of the language, `ToString`. These operations is used internally only by the engine and we don't use it in our code. Also, we can use `.toString()` like:

```javascript
let num = 23;
num.toString(); // "23"
```

or

```javascript
23..toString(); // "23"
```

As you might saw, when we use the number directly without storing it in a variable, we put extra (.) before `.toString()`, that's because the JS engine consider the first dot as a floating point like we type: `23.5`, while the second dot is related to the toString() method.

Also, when we explicitly converting from `String` into `Number` we use **Number()** constructor, e.g:

```javascript
Number("23"); // 23
```

or

```javascript
let str = "23";
alert(+str); // 23
```

Notice I used _+_ operator for explicit coercion from string to number which is a unary operator that get a single operand and converting it into number. The `Number()` uses the abstract operation **ToNumber** which defined in the specification.

##### Explicitly conversion into Boolean

We can convert any `non-boolean` value into `boolean` by using surprisingly the `Boolean()` constructor :) e.g:

```javascript
Boolean("23"); // true
```

or we can use `!!` operator

```javascript
!!23; // true
```

Notice here we use double `!` as the single `!` operator used to convert the value into `Boolean` then reverse it. Then the second `!` reverse the value again as it's reverse the reversion so the result is **true**.

##### Coercion of objects

When we explicitly convert object to any other data type, the engine uses an abstract operation which called **ToPrimitive** that uses `valueOf()` method which convert the object into its primitive value equivalent and if the `valueOf()` fails to get a primitive value then the **ToPrimitive** operation fall back into `toString()` method that converts the object into string which is primitive, e.g:

```javascript
var a = {
    valueOf: function () {
        return "33";
    }
}

Number(a); // 33

var a = {
    toString: function () {
        return "33";
    }
}

Number(a); // 33

Number([]); // 0

```

In the last example, the array is converted into number which produces 0.


**Implicit Coercion**

The second type of coercion is implicit coercion which is the conversion of type without intentionally convert it as it's hidden, non-obvious. This type of conversion confuse a lot of developers and make them avoid it and consider it a bug in javascript.

As the most of developers see `implicit coercion` evil, I see it from a different perspective as it's used to reduce a lot of boilerplate and details that's unnecessary. As **Kyle Sympthon** said in his book _YDKJS - Types & Grammar_ : **"Don't throw the baby out with the bathwater"** because the developers see implicit coercion evil they throw it away just to be safe, which is wrong.

Let's see how we can implicitly convert from type to another.

A `number` is implicitly converted into `string` by putting it in concatenation expression with a string, e.g:

```javascript
"2" + 2; // "22"
2 + "2"; // "22"
```

Here the _number_ 2 converted into _string_ by concatenate it with `string` "2". Let's consider this example:

```javascript
[2, 4] + [3, 6]; // "2, 43, 6"
```

Wait! What!, confusing hah! No, Not really.

While none of two operand are `string` the operation produces string. As the _ES5 Specification_ said that when "+" operator receive an object it uses _ToPrimitive_ operation which convert an object which is `non-primitive` into `primitive`, but which type? _Number_? or _String_?

Actually, the **ToPrimitive** operation uses under the hood the **ToNumber** operation which fails to produce a number then it falls back into `toString` method that convert the first array into string ("2, 4") and the second one into ("3, 6") then the operation becomes a normal string concatenation:

```javascript
"2, 4" + "3, 6"; // "2, 43, 6"
```

Obvious, hah!

A `string` is converted into `number` by adding the string in mathematical operation, e.g:

```javascript>
let a = "42";

a - 0; // 42
```

##### Implicitly converting from any value into Boolean

This's the most confusing part in implicit coercion. There's cases where implicit coercion to boolean happens:

- Expression in `if()` statement
- The test expression in `for(;..;)`
- The test expression in `while()` loop
- The test expression in ternary operators
- The left hand side in logical operators, `||, &&`

```javascript
let num = 2;

if (num) {
    alert("It's true !"); // It's true !
}
```

Here `num` implicitly converted into `Boolean` "true", then the test run and the alert fires because the number (2) is a _truthy_ value which means it converted into true when put in context of boolean.

You may notice that I said **"The left hand side in logical operators"**, the truth is these operators is not working like you expect they do similar to other languages like `PHP / Java`, actually it works differently, so, how is it working ? let's take an example:

```javascript
let b = 23;
let c = "Hi";

b && c; // "Hi"

b || c; // 23 
```

So, in the first expression, the test goes for the left hand side of the (&&) operator, convert it to boolean - which is truthy - then, return the right hand side. In the second expression the test goes for the left hand side, convert it to boolean - which is truthy also - then return it and doesn't go to the right hand side. This process is called **"Short circuit evaluation"**.

The use case for this concept is when you want to return a value depending on truthiness of another value like we do in `react`, so we use the (&&), also when you want to return a value and provide a fall back when the first value is falsy.

```javascript
// here we check if the array is empty, so don't return any thing or return a paragraphs containing the items of the array
{ arr.length > 0 && arr.map(item => {
    return <p>item</p>;
}) }

// here if the foo() returned undefined or null or any falsy values, the "no value returned" will be returned or the value returned from foo() will be returned either
{ foo() || "no value returned" }
```

##### == vs. ===

```javascript
2 == "2"; // true

2 === "2"; // false
```

Most of us will respond to this title: "== compares only values while === compares both types and values", actually this's completely wrong !

Both of them compares types and values, but the difference is if one of them permit coercion or not. In the first expression we'll notice that == operator permit the coercion from `string` to `number` so the result was `true`, while in the second expression the === doesn't permit coercion so the value was `false`.

###### Which is better ?

Other developers will argue wether is better and their teammates will respond: "of course === because it's much faster than ==", this's also wrong !

Um, yeah, there's a bit difference in performance but it's not considered because they are very close to each other, so, the final answer is: it doesn't matter which is faster, if you want to permit coercion, use ==, otherwise use ===, simply as that.

###### Comparing non-boolean to boolean

The most risky and confusing example that a lot if developers fall in is when comparing any value to `true` or `false`. Let's consider this example:

```javascript
1 == true; // true

"5" == true; // false
```

What ! How come !

The ES5 Spec said:

- if one of the two operand (x) is boolean return **ToNumber(x)** and compare them to each other.

So, when we compare 1 to `true` the boolean value "true" implicitly converted into number which is _1_, then **1 == 1** is obviously true, while in the second example when we compare "5" to `true`, the boolean value implicitly converted into number which is _1_ and the "5" converted into number which is _5_, so, **5 == 1** is obviously false.

- If either side of the comparison can be implicitly converted into `true` / `false`, Don't never ever use ==.

###### Comparing non-objects to objects

If an object is compared to a primitive value the ES5 Spec said:

- If any one of the two operands (x) is object and the other is primitive, return **ToPrimitive(x)** and compare them to each other.

Let's consider this example:

```javascript
2 == [2]; // true
```

Here the [2] converted into its primitive value which is _2_, then compare it to 2 which is obviously true.

Simple, hah!

Let's see this example:

```javascript
false == []; // true

[] == {}; // false
```

In the first example, false is converted into number - as we said above - which is _0_ and [] converted into number by ToPrimitive operation which is _0_ so the result was `true`, while in the second example, [] converted into number by ToPrimitive operation which is _0_ and {} converted into its primitive value which is _NaN_ so the result is `false`, as `NaN` never equal to itself or any other value.

Let's see this final example:

```javascript
[] == ![]; // true
```

Whaaaaaaaaat !

This's completely crazy !

Let's take it from right hand side, the ![] - by remember the rules of converting objects - the [] is first converted into boolean which is _true_ then negate it, so, the result of ![] is false, then compare true to [], **[] == false**, we saw this before and the result was `true`.

- If either side of comparison is object, Don't never ever use ==.

#### Conclusion

Coercion was - for many developers - an evil and confusing concept, it's the conversion from data type into another, it has 2 types, first is the `explicit coercion`, which is the intentionally converting from type into another, and `implicit coercion`, which is the hidden converting from type into another.

Implicit Coercion hides unnecessary details and simplify the implicitly.

When comparing any value to Boolean or to Object consider not using `==` operator as the coercion here make confusing and unpredicted results.

#### Sources

1. __*You Don't Know Javascript - Types & Grammar*__

2. [MDN Reference](https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion)