javascript - que - object instance of
¿Cuál es el operador instanceof en JavaScript? (10)
La palabra clave instanceof
en JavaScript puede ser bastante confusa cuando se la encuentra por primera vez, ya que las personas tienden a pensar que JavaScript no es un lenguaje de programación orientado a objetos.
- ¿Qué es?
- ¿Qué problemas resuelve?
- ¿Cuándo es apropiado y cuándo no?
¿Qué es?
Javascript es un lenguaje prototípico, lo que significa que usa prototipos para ''herencia''. el operador instanceof
comprueba si el tipo de propiedad prototype
una función constructora está presente en la cadena __proto__
de un objeto. Esto significa que hará lo siguiente (asumiendo que testObj es un objeto de función):
obj instanceof testObj;
- Compruebe si el prototipo del objeto es igual al prototipo del constructor:
obj.__proto__ === testObj.prototype
>> si esto estrue
instanceof
devolverátrue
. - Subirá la cadena del prototipo. Por ejemplo:
obj.__proto__.__proto__ === testObj.prototype
>> si esto estrue
instanceof
devolverátrue
. - Repetirá el paso 2 hasta que se inspeccione el prototipo completo del objeto. Si en ninguna parte de la cadena de prototipos del objeto se
testObj.prototype
contestObj.prototype
, el operadorinstanceof
devolveráfalse
.
Ejemplo:
function Person(name) {
this.name = name;
}
var me = new Person(''Willem'');
console.log(me instanceof Person); // true
// because: me.__proto__ === Person.prototype // evaluates true
console.log(me instanceof Object); // true
// because: me.__proto__.__proto__ === Object.prototype // evaluates true
console.log(me instanceof Array); // false
// because: Array is nowhere on the prototype chain
¿Qué problemas resuelve?
Resolvió el problema de verificar convenientemente si un objeto se deriva de un cierto prototipo. Por ejemplo, cuando una función recibe un objeto que puede tener varios prototipos. Luego, antes de usar métodos de la cadena de prototipos, podemos usar el operador instanceof
para verificar si estos métodos están en el objeto.
Ejemplo:
function Person1 (name) {
this.name = name;
}
function Person2 (name) {
this.name = name;
}
Person1.prototype.talkP1 = function () {
console.log(''Person 1 talking'');
}
Person2.prototype.talkP2 = function () {
console.log(''Person 2 talking'');
}
function talk (person) {
if (person instanceof Person1) {
person.talkP1();
}
if (person instanceof Person2) {
person.talkP2();
}
}
const pers1 = new Person1 (''p1'');
const pers2 = new Person2 (''p2'');
talk(pers1);
talk(pers2);
Aquí en la función talk()
primero se comprueba si el prototipo está ubicado en el objeto. Después de esto se elige el método apropiado para ejecutar. Si no se realiza esta comprobación, se puede ejecutar un método que no existe y, por lo tanto, un error de referencia.
¿Cuándo es apropiado y cuándo no?
Ya hemos repasado esto. Úselo cuando necesite verificar el prototipo de un objeto antes de hacer algo con él.
en vez de
El operando del lado izquierdo (LHS) es el objeto real que se está probando en el operando del lado derecho (RHS) que es el constructor real de una clase. La definición básica es:
Checks the current object and returns true if the object
is of the specified object type.
Aquí hay algunos buenos ejemplos y aquí hay un ejemplo tomado directamente del sitio del desarrollador de Mozilla :
var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral"; //no type specified
color2 instanceof String; // returns false (color2 is not a String object)
Una cosa que vale la pena mencionar es que instanceof
evalúa como verdadero si el objeto se hereda del prototipo de classe:
var p = new Person("Jon");
p instanceof Person
Eso es p instanceof Person
es cierto, ya que p
hereda de Person.prototype
.
Por solicitud del OP
He añadido un pequeño ejemplo con un código de ejemplo y una explicación.
Cuando declara una variable le da un tipo específico.
Por ejemplo:
int i;
float f;
Customer c;
Lo anterior le muestra algunas variables, a saber, i
, f
, y c
. Los tipos son integer
, float
y un tipo de datos de Customer
definido por el usuario. Tipos como los anteriores podrían ser para cualquier idioma, no solo para JavaScript. Sin embargo, con JavaScript cuando declara una variable no define explícitamente un tipo, var x
, x podría ser un número / cadena / un tipo de datos definido por el usuario. Entonces, ¿qué instanceof
hace? Comprueba el objeto para ver si es del tipo especificado, así que desde arriba, tomando el objeto Customer
que podríamos hacer:
var c = new Customer();
c instanceof Customer; //Returns true as c is just a customer
c instanceof String; //Returns false as c is not a string, it''s a customer silly!
Anteriormente hemos visto que c
fue declarada con el tipo Customer
. Lo hemos nuevo y hemos comprobado si es de tipo Customer
o no. Claro que sí, vuelve verdad. Luego, aún utilizando el objeto Customer
, verificamos si es una String
. No, definitivamente no es una String
hemos introducido un objeto Customer
no un objeto String
. En este caso, devuelve falso.
¡Es realmente así de simple!
Acabo de encontrar una aplicación del mundo real y ahora la usaré con más frecuencia, creo.
Si utiliza eventos jQuery, a veces desea escribir una función más genérica que también se puede llamar directamente (sin evento). Puede usar instanceof
para verificar si el primer parámetro de su función es una instancia de jQuery.Event
y reaccionar adecuadamente.
var myFunction = function (el) {
if (el instanceof $.Event)
// event specific code
else
// generic code
};
$(''button'').click(recalc); // Will execute event specific code
recalc(''myParameter''); // Will execute generic code
En mi caso, la función necesitaba calcular algo para todos (mediante un evento de clic en un botón) o solo un elemento específico. El código que utilicé:
var recalc = function (el) {
el = (el == undefined || el instanceof $.Event) ? $(''span.allItems'') : $(el);
// calculate...
};
Creo que vale la pena señalar que instanceof se define mediante el uso de la palabra clave "nueva" al declarar el objeto. En el ejemplo de JonH;
var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)
Lo que no mencionó es esto;
var color1 = String("green");
color1 instanceof String; // returns false
Al especificar "nuevo", se copió realmente el estado final de la función constructora de cadenas en la var de color1, en lugar de simplemente establecerlo en el valor de retorno. Creo que esto muestra mejor lo que hace la nueva palabra clave;
function Test(name){
this.test = function(){
return ''This will only work through the "new" keyword.'';
}
return name;
}
var test = new Test(''test'');
test.test(); // returns ''This will only work through the "new" keyword.''
test // returns the instance object of the Test() function.
var test = Test(''test'');
test.test(); // throws TypeError: Object #<Test> has no method ''test''
test // returns ''test''
El uso de "nuevo" asigna el valor de "esto" dentro de la función a la var declarada, mientras que al no usarlo asigna el valor de retorno.
Hay una faceta importante en la instancia que no parece estar cubierta en ninguno de los comentarios hasta ahora: la herencia. Una variable que se evalúa mediante el uso de instanceof podría devolver verdadero para múltiples "tipos" debido a la herencia prototípica.
Por ejemplo, definamos un tipo y un subtipo:
function Foo(){ //a Foo constructor
//assign some props
return this;
}
function SubFoo(){ //a SubFoo constructor
Foo.call( this ); //inherit static props
//assign some new props
return this;
}
SubFoo.prototype = new Foo(); // Inherit prototype
Ahora que tenemos un par de "clases", hagamos algunas instancias y descubramos de qué son instancias:
var
foo = new Foo()
, subfoo = new SubFoo()
;
alert(
"Q: Is foo an instance of Foo? "
+ "A: " + ( foo instanceof Foo )
); // -> true
alert(
"Q: Is foo an instance of SubFoo? "
+ "A: " + ( foo instanceof SubFoo )
); // -> false
alert(
"Q: Is subfoo an instance of Foo? "
+ "A: " + ( subfoo instanceof Foo )
); // -> true
alert(
"Q: Is subfoo an instance of SubFoo? "
+ "A: " + ( subfoo instanceof SubFoo )
); // -> true
alert(
"Q: Is subfoo an instance of Object? "
+ "A: " + ( subfoo instanceof Object )
); // -> true
¿Ves esa última línea? Todas las llamadas "nuevas" a una función devuelven un objeto que hereda de Object. Esto es cierto incluso cuando se usa la taquigrafía de creación de objetos:
alert(
"Q: Is {} an instance of Object? "
+ "A: " + ( {} instanceof Object )
); // -> true
¿Y qué hay de las definiciones de "clase" en sí mismas? ¿De qué son esas instancias?
alert(
"Q: Is Foo an instance of Object? "
+ "A:" + ( Foo instanceof Object)
); // -> true
alert(
"Q: Is Foo an instance of Function? "
+ "A:" + ( Foo instanceof Function)
); // -> true
Siento que entender que cualquier objeto puede ser una instancia de tipos MÚLTIPLES es importante, ya que usted (incorrectamente) asume que podría diferenciar entre, por ejemplo, un objeto y una función mediante el uso de instanceof
. Como este último ejemplo muestra claramente una función es un objeto.
Esto también es importante si está utilizando patrones de herencia y desea confirmar la progenie de un objeto por métodos distintos a la tipificación de pato.
Espero que ayude a cualquiera a explorar instanceof
.
Las otras respuestas aquí son correctas, pero no entienden cómo funciona realmente instanceof
, lo que puede ser de interés para algunos abogados lingüísticos.
Cada objeto en JavaScript tiene un prototipo, accesible a través de la propiedad __proto__
. Las funciones también tienen una propiedad prototype
, que es el __proto__
inicial para cualquier objeto creado por ellas. Cuando se crea una función, se le asigna un objeto único para el prototype
. El operador instanceof
usa esta singularidad para darle una respuesta. A continuación se muestra el instanceof
podría tener si lo escribieras como una función.
function instance_of(V, F) {
var O = F.prototype;
V = V.__proto__;
while (true) {
if (V === null)
return false;
if (O === V)
return true;
V = V.__proto__;
}
}
Esto es básicamente parafraseando la edición 5.1 de ECMA-262 (también conocida como ES5), sección 15.3.5.3.
Tenga en cuenta que puede reasignar cualquier objeto a la propiedad prototype
una función, y puede reasignar la propiedad __proto__
un objeto una vez que se haya construido. Esto le dará algunos resultados interesantes:
function F() { }
function G() { }
var p = {};
F.prototype = p;
G.prototype = p;
var f = new F();
var g = new G();
f instanceof F; // returns true
f instanceof G; // returns true
g instanceof F; // returns true
g instanceof G; // returns true
F.prototype = {};
f instanceof F; // returns false
g.__proto__ = {};
g instanceof G; // returns false
Sobre la pregunta "¿Cuándo es apropiado y cuándo no?", Mis 2 centavos:
instanceof
rara vez es útil en código de producción, pero útil en pruebas en las que quiere afirmar que su código devuelve / crea objetos de los tipos correctos. Al ser explícito sobre los tipos de objetos que su código está devolviendo / creando, sus pruebas se vuelven más poderosas como una herramienta para comprender y documentar su código.
Y puede usarlo para el manejo de errores y la depuración, como esto:
try{
somefunction();
}
catch(error){
if (error instanceof TypeError) {
// Handle type Error
} else if (error instanceof ReferenceError) {
// Handle ReferenceError
} else {
// Handle all other error types
}
}
instanceof
es solo azúcar sintáctica para isPrototypeOf
:
function Ctor() {}
var o = new Ctor();
o instanceof Ctor; // true
Ctor.prototype.isPrototypeOf(o); // true
o instanceof Ctor === Ctor.prototype.isPrototypeOf(o); // equivalent
instanceof
solo depende del prototipo de un constructor de un objeto.
Un constructor es simplemente una función normal. Estrictamente hablando, es un objeto de función, ya que todo es un objeto en Javascript. Y este objeto de función tiene un prototipo, porque cada función tiene un prototipo.
Un prototipo es solo un objeto normal, que se encuentra dentro de la cadena de prototipos de otro objeto. Eso significa que estar en la cadena de prototipos de otro objeto hace que un objeto sea un prototipo:
function f() {} // ordinary function
var o = {}, // ordinary object
p;
f.prototype = o; // oops, o is a prototype now
p = new f(); // oops, f is a constructor now
o.isPrototypeOf(p); // true
p instanceof f; // true
El operador instanceof
debe evitarse porque falsifica clases, que no existen en Javascript. A pesar de que la palabra clave de la class
tampoco está en ES2015, ya que la class
es de nuevo solo azúcar sintáctica para ... pero esa es otra historia.
//Vehicle is a function. But by naming conventions
//(first letter is uppercase), it is also an object
//constructor function ("class").
function Vehicle(numWheels) {
this.numWheels = numWheels;
}
//We can create new instances and check their types.
myRoadster = new Vehicle(4);
alert(myRoadster instanceof Vehicle);