Validación de clase: «instanceof»
El operador instanceof es utilizado para determinar si un objeto está asociado con una clase específica. Este operador también considera la herencia en su evaluación.
Este tipo de verificación es comúnmente necesario en diversas situaciones. En este contexto, lo utilizaremos para construir una función polimórfica que maneje argumentos de manera diferente según su tipo.
Uso del operador instanceof
La sintaxis básica es la siguiente:
obj instanceof Clase
Devuelve true si obj
pertenece a la clase Clase
o a una clase que hereda de ella.
Por ejemplo:
class Conejo {}
let conejo = new Conejo();
// ¿Es un objeto de la clase Conejo?
console.log(conejo instanceof Conejo); // true
También funciona con funciones constructoras:
function Conejo() {}
console.log(new Conejo() instanceof Conejo); // true
Y con clases integradas como Array:
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true
Es importante notar que arr
también pertenece a la clase Object
. Esto se debe a que Array hereda prototípicamente de Object.
Personalización con Symbol.hasInstance Si deseamos personalizar cómo funciona instanceof
, podemos definir un método estático Symbol.hasInstance
en la clase:
class Animal {
static [Symbol.hasInstance](obj) {
if (obj.puedeComer) return true;
}
}
let obj = { puedeComer: true };
console.log(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) es llamado
La mayoría de las clases no implementan Symbol.hasInstance
. En esos casos, se utiliza la lógica estándar: obj instanceof Clase
verifica si Clase.prototype
coincide con alguno de los prototipos en la cadena de prototipos de obj
.
En otras palabras, realiza comparaciones sucesivas como estas:
- ¿
obj.__proto__ === Clase.prototype
? - ¿
obj.__proto__.__proto__ === Clase.prototype
? - ¿
obj.__proto__.__proto__.__proto__ === Clase.prototype
? - …
Si alguna de estas comparaciones es verdadera, devuelve true. Si se alcanza el final de la cadena de prototipos sin coincidencias, devuelve false.
Por ejemplo:
class Animal {}
class Conejo extends Animal {}
let conejo = new Conejo();
console.log(conejo instanceof Animal); // true
El operador instanceof
evalúa si conejo
es una instancia de Animal
, tomando en cuenta la cadena de prototipos que hereda de Animal.prototype
.
Método isPrototypeOf
Existe otro método, isPrototypeOf
, que devuelve true si un objeto está en la cadena de prototipos de otro. Podemos reescribir obj instanceof Clase
como Clase.prototype.isPrototypeOf(obj)
.
function Conejo() {}
let conejo = new Conejo();
// Cambiemos el prototipo después de la creación
Conejo.prototype = {};
// ...ya no es un conejo!
console.log(conejo instanceof Conejo); // false
Esto muestra cómo cambiar el prototipo después de crear el objeto puede afectar el resultado de instanceof
.
Bonus: Object.prototype.toString para obtener el tipo Además de instanceof
, podemos usar Object.prototype.toString
para obtener una representación del tipo de un objeto.
Por ejemplo:
let obj = {};
console.log(obj); // [object Object]
console.log(obj.toString()); // lo mismo
Sin embargo, Object.prototype.toString
tiene una característica poderosa: puede ser utilizada como un typeof
extendido y como una alternativa a instanceof
.
let objectToString = Object.prototype.toString;
let arr = [];
console.log(objectToString.call(arr)); // [object Array]
Aquí, objectToString.call(arr)
ejecuta toString
en el contexto de arr
, devolviendo [object Array]
. Esto es útil para obtener el tipo real de un objeto en lugar de solo verificar su instancia.
Resumen En resumen, tenemos varios métodos para verificar tipos en JavaScript:
typeof
: para tipos primitivos, devuelve una cadena.Object.prototype.toString
: devuelve una cadena que representa el tipo de un objeto o primitivo.instanceof
: devuelve true o false dependiendo de si un objeto es una instancia de una clase específica, considerando la cadena de prototipos.
El operador instanceof
es particularmente útil cuando trabajamos con herencia de clases y queremos verificar la relación de herencia entre objetos y clases.