Falsy Values en Javascript

26 Ene 2011

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

Más:

{3} Comentarios.

  1. SaNTy

    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!

  2. dhamaso

    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).

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *