Entendiendo la coerción en JavaScript
Tags: javascript, coercion
Published: 2020-04-30 22:43:10

JavaScript es un lenguaje extraño… En el podemos encontrar cosas como

```javascript
console.log(1 == 1)      //true
// pero...
console.log([] == [])    //false
console.log([] == "")    //true

console.log(3 - "1")     //2
// pero...
console.log(3 + "1")     //"31"

console.log(NaN === NaN)              //false
console.log([1, 2, 3] + [4, 5, 6])    //"1,2,34,5,6"
console.log([] + {})                  //"[object Object]"
// y como olvidarnos de
console.log("b" + "a" + +"a" + "a")   // "baNaNa"
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/yu3mhfpydcjcsf90mlyl.gif)

Pero… esto no es tan extraño como parece! No son bugs, ni detalles que dejaron pasar y tampoco nadie se quedó dormido sobre el teclado mientras escribía las especificaciones del lenguaje (eso espero 😅), todas estas cosas tienen sentido y suceden por algo llamado **coerción.**

En JavaScript, la coerción es una característica que **fuerza a una variable de cierto tipo a tener el comportamiento de una diferente**

Por ejemplo:

```javascript
console.log("3" - 1)  //2
```

En este caso, el string "3" está siendo forzado a comportarse como un número para poder completar correctamente la operación matemática esperada.

## 🤔 Por qué necesitamos esto?

JavaScript es un lenguaje débilmente tipado, eso quiere decir, que no tienes que especificar el tipo de variables porque el lenguaje va a inferirlo de manera automática. Esto también quiere decir, que el tipo de la variable va a estar asociado con su valor.

Esto es también llamado **“Duck typing”**. Este nombre viene de un test utilizado en razonamiento inductivo atribuido a James Whitcomb Riley que dice “Si camina como un pato y grazna como un pato, entonces debe ser un pato”, a lo que el autor se refiere con esto, es que podemos identificar la naturaleza de un objeto solamente observando sus características, y esto es justo lo que hacen los lenguajes de programación que permiten tipados dinámicos, donde solo debemos preocuparnos por lo que la variable va a hacer y no por su tipo.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/92tvjyf259o1w7cq35zs.gif)

Pero esto no es tan bueno en todos los escenarios, ya que podemos terminar haciendo cosas extrañas…

```javascript
var duck = true;
var peanuts = 10;
var sum = duck + peanuts  // true + 10... WHAT!? 🤯
```

Para evitar arrojar errores en estos casos, como muchos otros lenguajes lo harían, JavaScript establece a través de la coerción algunas reglas para manejar estos escenarios.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6ic27stw04hqbffnw9io.png)

## Operador de igualdad (==)

Este operador compara los valores que hay al lado izquierdo y derecho de el, cuando son del mismo tipo compara los valores y de ser iguales retorna `true` y de lo contrario `false`.

Cuando al utilizar este operador se tengan a ambos lados de la operación diferentes tipos de datos, el comportamiento será:

| x | y | resultado |
|---|---|--------|
| null | undefined | true |
| undefined | null | true |
| number | string | x == toNumber(y) |
| string | number | toNumber(x) == y |
| boolean | any | toNumber(x) == y |
| any | boolean | x == toNumber(y) |
| string, number, or symbol | Object | x == toPrimitive(y) |
| Object | string, number, or symbol | toPrimitive(x) == y |
| otros casos | | false |

Ejemplos:

```javascript
1 == "1"              //true
1 == "one"            //false
true == 1             //true
false == "zero"       //false
"test" == {x:"test"}  //false
```

Puedes encontrar mas información en la [especificación de ECMA](https://www.ecma-international.org/ecma-262/#sec-abstract-equality-comparison)

## Operador de adición (+)

Al utilizar el operador de adición, si ambos lados de la operación son números, se realizará la operación matemática suma, de lo contrario, se concatenarán los valores de ambos lados como Strings.

Ejemplos:

```javascript
1 + 1                       //2
1 + "1"                     //11
"hello" + " world"          //"hello world"
"It's " + true              //"It's true"
"pizza" + {cheese: "extra"} //"pizza [object Object]
```

Puedes encontrar mas información en la [especificación de ECMA](https://www.ecma-international.org/ecma-262/#sec-addition-operator-plus)

## Operador de sustracción (-)

Este operador siempre realizará la operación matemática restar, en el caso de que ambos lados no sean números, los strings y booleans son convertidos a números y se realiza la operación matemática, en otros casos el resultado será NaN (Not a Number).

Ejemplos:

```javascript
3 - 2      //1
"3" - 2    //1
3 - true   //2
1 - {x:3}  //NaN
"fun" - 2  //NaN
```

Puedes encontrar mas información en la [especificación de ECMA](https://www.ecma-international.org/ecma-262/#sec-subtraction-operator-minus)

## Truthy y Falsy

Un valor **truthy** es aquel que evaluado en un contexto booleano da como resultado true, del mismo modo, un valor **falsy** es aquel que evaluado en un contexto booleano da como resultado false, en JavaScript todos los valores son true excepto:

- false
- 0
- ""
- ''
- null
- undefined
- NaN

## Casos especiales: Objetos

En JavaScript también nos encontramos con esto:

```javascript
[] + {}   //[object Object]
{} + []   //0
```

Probablemente despues de leer las reglas de coerción del operador de adición sigas sin entender porque sucede esto, y es porque este es un caso especial.

### **Primer caso:** `[] + {}`

```javascript
[] + {}
String([]) + String({}) //Ambos lados de la operación son      convertidos a string para ser concatenados
'' + '[object Object]'  //Se concatenan los resultados
'[object Object]'       //Valor resultante
```

### **Segundo caso:** `{} + [] = 0`

En este caso, lo que sucede es que los brackets vacíos al inicio `{}` son interpretados como bloque de código vacío, por lo cual son ignorados por JS.

```javascript
{} + []
+[]                   //JS ignora el lado izquierdo de la operación
Number([])            //El lado restante es convertido a número
0                     //Valor resultante
```

## Conclusión

La coerción es una de las características mas curiosas de JavaScript y la considero de gran importancia para aprender ya que hay resultados que muchas veces no sabemos como explicar y podemos pasar mucho tiempo pensando que es un error en la lógica de nuestro código, cuando en realidad, es una característica del lenguaje.
Y finalmente… JavaScript no es tan raro después de todo ✨

## Reto

Deja en los comentarios cuales de las siguientes lineas de código van a ser mostradas (no se vale utilizar la consola 😅).

```javascript
if('3' + 2 == 5) { console.log("Pizza"); }

if([]) { console.log("Cheese"); }

if( 4 + "1" == 5) { console.log("Spaghetti"); }

if(0) { console.log("Yogurt"); }

if(5 + true == 6) { console.log("Carrot"); }

if(!undefined) { console.log("Bunny"); }

if({} == {}) { console.log("Panda"); }

if(["3"] - 1 == 2) { console.log("Salt"); }

if('' == []) { console.log("Cookie"); }
```

### Referencias:

- https://www.ecma-international.org/ecma-262/
- http://www.etnassoft.com/2011/04/06/coercion-de-datos-en-javascript/
- https://hackernoon.com/understanding-js-coercion-ff5684475bfc
- http://2ality.com/2012/01/object-plus-object.html