Contenido

Detectar el tipo de una variable en Javascript

13 ene

+ 3

Cuando intentamos detectar si una variable que estamos usando en nuestros scripts Javascript podemos usar operadores como typeof que nos devolverá el tipo de variable que estamos usando, pero ¿es la forma correcta?

typeof null; // "object"
typeof []; // "object"

instanceOf / .constructor

Por desgracia typeof es un operador ya bastante viejo y nos arroja resultados un poco ambiguos y en ocasiones nos hacen ir hacia atrás en lugar de avanzar. Las nuevas revisiones de Javascript, arrojan un poco de luz en la detección del tipo de variables usados mediante 1 operador y/o una propiedad de las variables.

Operador instanceof

Nos permite comprobar si un elemento es de un tipo concreto informándolo previamente.

var a = [];
a instanceof Array; // True
a instanceof String; // False

De esta forma podremos validar más certeramente el tipo que estamos esperando para una variable de nuestro script.

Propiedad .constructor

También podemos preguntarle a la variable que constructor ha sido empleado con ella, para ello deberemos hacer uso de la propiedad constructor de la propia variable.

var a = [];
a.constructor == Array;

¿Cual es mejor?

Ambos métodos nos ayudan a detectar, mucho más fiablemente, el tipo de variable que estamos usando pero una es más rápida que otra.

Para probarlo, como casi todas las pruebas de este tipo he creado un pequeño script que lanza 10.000 y 100.000 consultas de cada uno de los métodos a 2 variables iguales y los resultados hablan por si solos.

La prueba:

var t = new Date().getTime();
for (var x =0; x<10000; x++){
    var a = [];
    a instanceof Array;
}
console.log(new Date().getTime() - t);

var t = new Date().getTime();
for (var x =0; x<10000; x++){
    var b = [];
    b.constructor == Array
}
console.log(new Date().getTime() - t);

Los resultados

10.000 100.000
instanceof 32 351
.constructor 82 813

¿Problemas?

Pues claro, no iba a ser todo tan fácil como parecía :D

Aparecen problemas cuando se crean multiples entornos DOM mediante el uso de frames. En pocas palabras, los arrays creados dentro de un <iframe /> no son iguales que los contenidos en otro <iframe />, sus constructores son diferentes por lo tanto ambas propiedades fallan.

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]  

// Boom!
arr instanceof Array; // false  

// Boom!
arr.constructor === Array; // false

Douglas Crockford lo comentó por allá sobre el 2003 y como solución propuso que se comprobara alguno de los métodos del Array para detectar si este es una función o no.

typeof myArray.sort == 'function'

En Prototype.JS 1.6.0.3 usan un método parecido para detectar si se trata de un Array usando este sistema.

function isArray(object) {
  return object != null && typeof object === "object" &&
    'splice' in object && 'join' in object;
}

Aunque esto nos vuelve a generar otra problemática, las variables de tipo “object” también poseén esos métodos y si comparamos un objeto con isArray() técnicamente devolverá un TRUE como una casa. Por ello Perfection Kills propone una solución más sencilla con la que detectar un Array y dejar de tener problemas con los multiframes.

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

Personalmente no me gusta, ya que dependemos de una cadena que los desarrolladores del motor JS del navegador del usario para detectar el tipo de variable que estamos usando, si por algún motivo alguien usó [object array] en lugar de [object Array] ya volvemos a tener uno de los problemas que typeof nos ha estado dando hasta hace poco.

Comentar

#

Me reservo el derecho de eliminar y/o modificar los comentarios que contengan lenguaje inapropiado, spam u otras conductas no apropiadas en una comunidad civilizada. Si tu comentario no aparece, puede ser que akismet lo haya capturado, cada día lo reviso y lo coloco en su lugar. Siento las molestias.