loading...

Entendiendo la coerción en JavaScript

manucastrillonm profile image Manu Castrillon ・4 min read

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

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

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:

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

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

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

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:

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

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:

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

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:

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

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:

[] + {}   //[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: [] + {}

[] + {}
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.

{} + []
+[]                   //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 😅).

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:

Posted on Apr 30 by:

manucastrillonm profile

Manu Castrillon

@manucastrillonm

@GitHub Campus Expert 🚩| co-organizer of @gitConfCO | @vuevixensCO chapter leader 🦊

Discussion

markdown guide
 

Me gustó mucho este post, muy interesante conocer el comportamiento de Javascript