Javascript tiene, entre sus tipos de datos, soporte para valores booleanos (Boolean Object), los cuales pueden corresponder con true o false. Estos valores se asignan de forma explícita mediante el constructor Boolean:
var foo = new Boolean( 'true' ); |
Además de este tipo, cada elemento del lenguaje posée también un valor booleano intrínseco-primitivo (Boolean value) que conocemos como verdadero (truthy) o falso (falsy) dependiendo del mismo. Este tipo de valor, completamente diferente al del objeto anterior, puede determinar el comportamiento de los condicionales e igualdades si no son tenidos en cuenta.
En este artículo revisaremos todos los supuestos para evitar incurrir en los errores que pueden surgir por el desconocimiento de los que llamamos los falsy values.
Valores Booleanos en Javascript
Es importante no confundir los valores booleanos primitivos con los valores del objeto booleano. Cualquier objeto cuyo valor no es undefined o null, incluyendo los Boolean Object cuyo valor es false, se evalúan como true cuando son comparados con otro término. Esto queda más claro con un ejemplo:
x = new Boolean(false); // Boolean Object if( x ){ // La condición se cumple porque x ha sido definida // con un valor verdadero (truthy) } |
Este comportamiento, sin embargo, no se aplica a la primitiva boolenana:
x = false; // Primitive boolean value if( x ){ // La condición no se cumple porque x aunque se ha definido // posée un valor falsy } |
Una vez tenida en cuenta la diferencia, debemos conocer también cómo el comportamiento de aquellos valores falsy puede llegar a resultar desconcertante, especialmente cuando comparamos variables en modo no-estricto.
Falsy Values
Los siguientes valores, extraídos del Apéndice A.12 del Good Parts de Crockford, evalúan siempre como false en una comparación:
var a = 0; // (cero) -> Number var b = NaN; // (Not a Number) -> Number var c = ""; // (cadena vacía) -> String var d = false; // -> Boolean var e = null; // -> Object var f = undefined; // -> Undefined |
Truthy Values
Cualquier otro valor diferente de los anteriores, es considerado como verdadero (truthy), incluído Infinity (otro número especial como NaN), «0» (cero entrecomillado), «false» (false entrecomillado), funciones vacías, arrays vacíos y objetos vacíos:
var t = Infinity; // -> Number var u = "0"; // -> String var v = "false"; // -> String var x = function(){}; // -> Function var y = []; // -> Object (Array) var z = {}; // -> Object |
Comparando valores Falsy
Las comparaciones entre aquellos valores que hemos denominado falsy siguen una serie de reglas muy poco intuitivas. El algoritmo de comparación utilizado en la especificación ECMAScript para comparaciones no-estrictas podemos consultarlo en el punto 11.9.3 mientras que aquellas estrictas están descritas en el 11.9.6.
Como punto a destacar, hay que señalar que los valores false, 0 (cero) y «» (cadena vacía) son equivalentes y pueden compararse entre sí utilizando el operador de igualdad no-estricto ‘==’:
var a = false; var b = 0; var c = ""; console.log( a == b ); // true console.log( b == c ); // true console.log( a == c ); // true |
Los valores null y undefined no mantienen equivalencia con ningún otro valor salvo con ellos mismos:
console.log( false == null ); // false console.log( false == undefined ); // false console.log( null == null ); // true console.log( undefined == undefined ); // true |
Finalmente, el valor NaN (Not a Number), reservado para valores que no son números, no mantiene equivalencia con ningún otro valor, ni siquiera con sigo mismo:
console.log( NaN == null ); // false console.log( NaN == false ); // false console.log( NaN == NaN ); // false |
NOTA: Pese a que NaN se identifica con aquellos valores que no son números, pertenece al tipo de datos Number:
console.log( typeof NaN ); // Number |
Para prevenir errores derivados de las reglas de comparación no-estricta en aquellos casos en los que pueden aparecer valores falsy como operadores, la opción segura es utilizar el modo estricto ‘===’, asegurándonos de que los términos se comparan tanto en tipo de datos como en valor:
console.log( false == 0 ); // true console.log( false === 0 ); // false |
Estructuras condicionales
Cuando hablamos de condicionales, los valores falsy pueden resultar interesantes para simular comportamientos que no están presentes de forma nativa en Javascript.
Para sacar partido de estas estructuras, tenemos que conocer su funcionamiento, por lo que es interesante recordarlo: en Javascript, las condiciones son evaluadas de izquierda a derecha. Esto quiere decir que para los casos en que disponemos de una estructura como la siguiente
if( condition1 && condition2 && condition3 ) |
si la primera condición corresponde a un valor falsy, no se continúan evaluando los siguientes términos. Esto es propio de cualquier lenguaje de programación cuyo flujo interno se corresponde con un sistema booleano lógico en cortocircuito: la evaluación de una expresión lógica se detiene tan pronto como se determina su resultado. Por esta razón, es recomendable el ubicar aquella condición más susceptible de ser falsy al principio manteniendo aquellas que requieren de un mayor procesado al final.
También tenemos que considerar que los operadores booleanos «||» y «&&» tienen en Javascript un comportamiento diferente al de otros lenguajes de programación. Por ejemplo, en PHP, el resultado de un condicional será siempre TRUE o FALSE mientras que en Javascript, el condicional devuelve el valor de la última condición evaluada correctamente. En el siguiente caso,
if( condition1 || condition2 ) |
si condition1 es truthy (cualquier valor distinto a falsy), el resultado del condicional será true. Pero, si usamos el condicional como un estamento, es decir, asignándolo a una variable, entonces el resultado será el valor de condition1.
var foo = 'Hello World'; // Truthly value -> string var bar = 'Silence'; // Truthly value -> string var result = ( foo || bar ); console.log( result ); // Hello World |
El valor devuelto por el condicional siempre corresponde con el del primer término evaluado correctamente. En este caso, ‘foo‘ es un valor truthy, una cadena, por lo que es asignado a la variable result. De haber correspondido a un valor falsy, se continuaría evaluando el siguiente término:
var foo = false; // Falsy value var bar = 'Silence'; // Truthly value -> string var result = ( foo || bar ); console.log( result ); // Silence |
Si ambos términos correspondieran con un valor falsy, se proseguiría con el siguiente hasta encontrar uno válido con el que establecer una asignación:
var result = ( foo || bar || another_var || and_another_one || n... ) |
Si ningún término evaluase verdadero (es decir, todos son falsy) el resultado sería entonces el valor correspondiente al último de los términos:
var foo = false; var bar = NaN; var result1 = ( foo || bar ); var result2 = ( bar || foo ); console.log( result1 ); // NaN console.log( result2 ); // false |
Este comportamiento nos permite asignar valores por defecto a aquellas variables con valor falsy; por ejemplo, aquellos métodos sin definir en un objeto:
var myCar = {}; myCar.pilot = ( myCar.pilot || 'Etnas' ); console.log( myCar.pilot ); // Etnas |
Ya que en un objeto, un método sin definir devuelve un tipo de dato Undefined (un valor falsy), podemos asignarle un valor por defecto utilizando un término truthy como último término de un condicional.
Es la misma técnica que empleamos, por ejemplo, para asignar valores por defecto a los argumentos de una función:
function cutString( userString, maxChars ){ maxChars = maxChars || 10; return userString.substr( 0, maxChars ); } var test = "Supercalifragilisticexpialidocious"; console.log( cutString( test ) ); // Supercalif console.log( cutString( test, 20 ) ); // Supercalifragilistic |
Al no proporcionar un valor para el segundo argumento, dentro del contexto de la función recibe un tipo de datos undefined (un falsy). Utilizando un condicional, asignamos un valor por defecto que permite continuar con el flujo de la función sin provocar errores.
Conclusión
Javascript asigna un valor booleano (primitivo) automáticamente a todos los elementos del lenguaje. A dichos valores los llamamos truthy o falsy dependiendo de cómo el intérprete los maneja.
Ese valor, diferente al del propio Objeto Booleano, determina por ejemplo el comportamiento de las estructuras de control y el resultado en comparaciones de igualdad no-estricta. Los valores que hemos denominado falsy son aquellos que siempre se evaluarán como ‘falsos’ en los casos anteriores pudiendo provocar comportamientos inesperados y errores difíciles de rastrear.
Sin embargo, conociendo cómo actúan, podemos aprovecharlos para añadir a nuestros códigos funcionalidades interesantes propias de otros lenguajes. Un ejemplo de esto, sería el asignar valores por defecto tanto a las propiedades de un objeto como a los argumentos de una función.
En este artículo hemos repasado las combinaciones más frecuentes que pueden darse entre estos valores y elaborado algunos ejemplos útiles de uso.
Más información
Valores Booleanos en Javascript, Boolean API
ECMAScript Language Specification Non Official Version
Carlos Benítez, Operadores de Igualdad en Javascript
Wooow, hermoso artículo 😛
Tengo cerca de un año programando en JS y no me ha dejado de sorprender la versatilidad de este lenguaje. Y con tus artículos super explicados he aprendido muchísimo….me encanta tu blog y por supuesto JS!
Primeramente, yo creo muy sinceramente que en la red no hay otro mejor que tu explicando estos temas, segundo seria bueno que explicaras tambien algo sobre typecasting :
http://jibbering.com/faq/notes/type-conversion/
Si lo pudieras explicar seria genial.
un saludo y hasta pronto (I’ll be back).
Hola!
Gracias por el feedback!
Tienes un artículo sobre la coerción de tipos aquí:
EtnasSoft | Coerción de datos en Javascript
Espero que te resulte útil.
Saludos!