Hamburger Icon
Las cosas más raras que verás en JavaScript

Las cosas más raras que verás en JavaScript

A JavaScript se le quiere mucho, pero es peculiar. Hay que aceptarlo. Tiene cosas... un poco raras, pero todas ellas tienen una explicación.

Vamos a ver un primer ejemplo de los que te dejan 🤯

Comparación de un array vacío con su negación

const valor = [] == ![] // valor = true

Un array vacío es lo mismo que la negación de si mismo. ¿Cómo puede ser? Paso a paso. El operador == convierte los dos lados de la comparación en números para evaluarlos. Un array vacío se convierte en el valor 0, y la negación de un array vacío también, por lo que:

const valor == [] == ![] // la operación se transforma en 0 == 0
0 == 0 // true

Con lo anterior, podemos deducir esto:

![] == true // false
[] == true // false

Ni un array vacío ni su negación son true, porque como hemos dicho hace un momento los dos se convierten en el valor 0, que evalúa a false.

Number(![]) // 0
Number([]) // 0
Number(true) // 1

Si quieres evitar situaciones aparentemente raras, usa siempre el operador === para hacer comparaciones.

const valor = [] === ![] // valor = false

El operador == compara los dos valores después de hacer conversiones, no pasa lo mismo con ===, que solo hará la conversión si los dos valores son similares.

¿Es verdadero lo falso?

Mira esto:

!!"false" == !!"true" // true
!!"false" === !!"true" // true

La doble negación se usa para convertir el valor de cualquier tipo a su correspondiente valor Booleano true o false.

En JavaScript true es 1 y false es 0, mientras que la cadena de texto "true" o "false" no son un número (NaN en JavaScript de Not a Number).

Las cadenas de texto son valores truthy, es a decir, evalúan a true siempre y cuando no estén vacías. Si ya conocías los valores truthy y falsy entonces este ejemplo no te habrá sorprendido demasiado.

¿Qué pasa entre null y el valor 0?

Estos dos tienen una relación que puede parecer rara a primera vista. ¿Quieres saber por qué? Empecemos:

null == 0 // false

Vale... Seguimos:

null > 0 // false

Ok... Hasta aquí todo bien. Pero mira:

null >= 0 // true

¿WTF? ¿Cómo es posible esto? No parece tener sentido. Si null no es igual a 0 y tampoco es mayor que 0, entonces, ¿por qué sí es mayor o igual a 0? Esto es debido a que los operadores == y >= no funcionan del mismo modo.

El valor null cumple siempre una regla especial: no es igual a absolutamente nada, por eso la primera comparación es falsa. El operador >= convierte null en el valor 0, por eso la segunda expresión es falsa y la tercera verdadera.

Comparaciones locas 🙈

Los operadores de comparación los podemos usar para comparar tres números, así:

1 < 2 < 3 // true

Pero mira qué pasa cuando lo planteas al revés:

3 > 2 > 1 // false

Aunque no lo parezca, en nuestro mundo de JavaScript esto tiene todo el sentido del mundo:

// Estas dos expresiones son equivalentes:
1 < 2 < 3 // 1 < 2 es lo mismo que true
true < 3 // esto tambiés es true, porque se evalúa como 1 < 3

// Ahora bien, si lo hacemos al reves...
3 > 2 > 1 // 3 > 2 es true
true > 1 // false, porque se evalúa como 1 > 1

Como matemáticamente operamos de izquierda a derecha, al seguir este orden llegamos a true > 1, lo cual es falso.

Suma de valores en coma flotante

Aquí siempre me peta la cabeza.

0.1 + 0.2 == 0.3 // false

Esto no se hace JavaScript, esto es jugar con las leyes de la física:

0.1 + 0.2 // 0.30000000000000004

Los números en coma flotante en JavaScript no son del todo precisos, por eso la comparación nos da false. Algunos pensarán que esto es cosa solo de JavaScript, pero nada más lejos de la realidad, estos problemas de precisión en los números flotantes lo tienen también los demás lenguajes de programación.

Es muy importante conocer qué está sucediendo para que esto no sea un problema. Los números en coma flotante se representan siguiendo el estándar IEEE 754.

Cuando queremos representar el número 0.1, como trabajamos en base 10 lo que se hace es 1/10. En este caso, es 0.1. El problema viene con los números que nos dan infinitos decimales. En base 10 no podemos representar el valor de 1/3 porque el resultado es una secuencia infinita 0.333333.... Si intentas representar 1/3 en base 3, entonces obtienes 0.1.

Los ordenadores operan en base 2, binario, empleando solo 1 y 0 como valores. Algunos valores se pueden representar de forma precisa y otros necesitan infinitos decimales, por lo que se usan aproximaciones.

Cuando hacemos operaciones con valores flotantes, en memoria se guardan los valores aproximados a su represencación con este formato, cuando no pueden ser exactas. Por este motivo, una suma tan sencilla como la del ejemplo no arroja el resultado esperado, porque en memoria se ha guardado una aproximación al valor, y con esa aproximación hemos operado.

Suma de booleanos

¿Para qué vas a sumar booleanos? Pues no sé, pero mira:

true + false // 1

A estas alturas del post, ya sabes que JavaScript transforma los dos lados de la operación a valores numéricos y que, true y false son respectivamente 1 y 0. ¿Tiene sentido verdad?

Más sumas raras...

Otra para dejarte KO:

const valor = [1, 2, 3] + [4, 5, 6] // 1,2,34,5,6

Lo que sucede es que los arrays se convierten en strings y luego se concatenan.

Creo que es mejor no combinar arrays y operaciones de suma 😂

Conclusiónes

JavaScript puede llegar a parecer muy raro, sí. Pero al final todo tiene su sentido y su motivo de ser así. Contra más conozcas el lenguaje más controladas tendrás muchas situaciones que pueden parecer un sinsentido. ¿Recuerdas algún bug que te tuviera horas y horas pensando dónde estaba el problema y no poder resolverlo? Puede ser que fuera por uno de estos comportamientos que a priori pueden parecer raros.

Hay muchas otras situaciones locas como estas, pero creo que ya te puedes hacer una idea. Cuando veas algo que parece no cuadrar, recuerda: cuando se hacen operaciones puede ser que JavaScript transforme los operandos para poder dar un resultado correcto. Si te sientes con ánimos, prueba este test a ver si haces pleno: JS Is Weird.