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"
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.
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.
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"); }
Top comments (1)
Me gustó mucho este post, muy interesante conocer el comportamiento de Javascript