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 😀
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.
3 comentarios, 0 referencias
+
#