Javascript isArray() definitivo

08 Feb 2011

Tras comentar con un colega el último post sobre Duck Typing, me lanzó un desafío: crear la función isArray() definitiva para Javascript.

Es cierto que la mayoría de lenguajes poséen un método para identificar si el tipo de datos de una variable corresponde con un Array, pero Javascript no es uno de ellos. Es por eso que hace falta implementarlo por nosotros mismos igual que hacen las principales librerías como jQuery, Mootools o Dojo.

Después de hacer muchas pruebas y refactorización, he llegado a dos soluciones válidas para todos los casos: una utilizando la herencia prototípica y la otra siguendo la metodología del Duck Typing.

Ambas han sido probada en varios entornos con idénticos resultados en rendimiento y fiabilidad.

Método 1 (herencia o prototípica)

function isArray(obj){
  return Object.prototype.toString.call( obj ) === "[object Array]";
}

Este método, parcialmente modificado, es el utilizado por ejemplo por Prototype o Underscore.

Método 2 (mediante el Duck Typing)

function isArray(obj){
  return obj && !!obj.push;
}

Probando las funciones

Tomando las siguientes declaraciones:

var a = [],
    b = [1,2,3,4],
    c = new Array(1,2,3,4),
    d = 'Hello World';

Ambas funciones devuelven el resultado esperado:

console.log( isArray( a ) ); // true
console.log( isArray( b ) ); // true
console.log( isArray( c ) ); // true
console.log( isArray( d ) ); // false

A diferencia de instanceof(), tampoco tienen problemas en detectar el tipo a través de iframes:

var iframe = document.createElement( 'iframe' );
document.body.appendChild( iframe );
xArray = window.frames[window.frames.length-1].Array;
 
var arr = new xArray(1,2,3); // [1,2,3]  
 
console.log( arr instanceof Array ); // false
console.log( arr.constructor === Array ); // false
console.log( isArray( arr ) ); // true

Finalmente, ambas distinguen correctamente entre el objeto arguments (tan similar a un array) y un array genuino:

function test(){
  return arguments;
}
 
console.log( isArray( test( 1, 2, 3, 4 ) ) ); // false

En definitiva, cualquiera de estas dos aproximaciones funcionan correctamente y permiten averiguar si el objeto evaluado es o no un array.

Más:

{4} Comentarios.

  1. Gaston Carrizo

    Hola, antes que nada quiero felicitarlos por la clara explicación de algo que en principio parece sencillo pero que no lo es tanto. Les escribo para que si fuese posible me expliquen el porqué de la doble negación al método push (metodo 2)… es decir, no es lo mismo preguntar «if( obj.push )» que «if( !!obj.push )» ?

    Gracias por adelantado.
    Saludos.

    Gaston.

  2. Uziel

    Hola, excelente blog. Una pregunta con el Método 2 (mediante el Duck Typing) es posible que se «confunda» si yo creo un objeto (no sé… myPila) en el cual deba de declararle el método push, que pasaría en este caso?? seguiría funcionando ó hay que tener cuidado con no declarar esté método en las clases ??

    Saludos… de antemano gracias por la respuesta

    • Carlos Benítez

      Hola Uziel;
      ese es el problema del Duck Typing: que si solo comprobamos un determinado método en un objeto, corremos el riesgo de que en él, se haya definido uno con el mismo nombre que estamos testeando. De ahí que, por lo general, preguntemos siempre por más de uno.

      De todos modos, el Duck Typing es, como suelo decir, una comprobación ‘de andar por casa’; no deberíamos depender de él en una aplicación crítica donde la validación de datos es fundamental. Para este tipo de escenarios, podemos utilizar otros métodos más robustos como por ejemplo el descrito en: ‘Cómo obtener el tipo de datos preciso de una variable en Javascript‘.

      Saludos!

Deja un comentario

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