Le mot clé instanceof
en JavaScript peut être assez déroutant lorsqu'il est rencontré pour la première fois, car les gens ont tendance à penser que JavaScript n'est pas un langage de programmation orienté objet.
L'opérande côté gauche (LHS) est l'objet actuellement testé sur l'opérande côté droit (RHS) qui est le constructeur effectif d'une classe. La définition de base est:
Checks the current object and returns true if the object
is of the specified object type.
Voici quelques bons exemples et voici un exemple tiré directement de site de développement 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)
Une chose à noter est que instanceof
est évalué à true si l'objet hérite du prototype de la classe:
var p = new Person("Jon");
p instanceof Person
C'est-à-dire que p instanceof Person
est vrai puisque p
hérite de Person.prototype
.
J'ai ajouté un petit exemple avec un exemple de code et une explication.
Lorsque vous déclarez une variable, vous lui attribuez un type spécifique.
Par exemple:
int i;
float f;
Customer c;
Ce qui précède vous montre quelques variables, à savoir i
, f
et c
. Les types sont integer
, float
et un type de données défini par l'utilisateur Customer
. Des types tels que ceux ci-dessus pourraient être pour n'importe quelle langue, pas seulement JavaScript. Cependant, avec JavaScript lorsque vous déclarez une variable, vous ne définissez pas explicitement un type, var x
, x peut être un nombre/une chaîne/un type de données défini par l'utilisateur. Donc, ce que instanceof
vérifie l'objet pour voir s'il est du type spécifié. Ainsi, en prenant l'objet précédent Customer
, nous pourrions le faire:
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!
Ci-dessus, nous avons vu que c
était déclaré avec le type Customer
. Nous l'avons à nouveau et vérifié s'il est de type Customer
ou non. Bien sûr, ça retourne vrai. Puis, en utilisant toujours l’objet Customer
, nous vérifions s’il s’agit d’un String
. Non, certainement pas un String
nous avons créé un objet Customer
et non un objet String
. Dans ce cas, il retourne faux.
C'est aussi simple que ça!
Il existe une facette importante dans un exemple de ce qui ne semble pas être couvert par aucun des commentaires jusqu'à présent: l'héritage. Une variable évaluée à l'aide d'instanceof pourrait renvoyer true pour plusieurs "types" en raison d'un héritage de prototype.
Par exemple, définissons un type et un sous-type:
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 = Object.create(Foo.prototype); // Inherit prototype
SubFoo.prototype.constructor = SubFoo;
Maintenant que nous avons quelques "classes", faisons quelques instances et découvrons à quoi elles correspondent:
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
Voir cette dernière ligne? Tous les "nouveaux" appels à une fonction renvoient un objet qui hérite de Object. Ceci est vrai même lorsque vous utilisez un raccourci pour la création d'objet:
alert(
"Q: Is {} an instance of Object? "
+ "A: " + ( {} instanceof Object )
); // -> true
Et que dire des définitions de "classe" elles-mêmes? De quoi sont-ils des exemples?
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
Je pense qu'il est important de comprendre que tout objet peut être une instance de plusieurs types est important, puisque vous supposez (à tort) que vous pouvez différencier, par exemple, et objet et une fonction en utilisant instanceof
. Comme ce dernier exemple montre clairement une fonction est un objet.
Cela est également important si vous utilisez des modèles d'héritage et souhaitez confirmer la descendance d'un objet à l'aide de méthodes autres que le typage de canard.
Espérons que cela aide tous ceux qui explorent instanceof
.
Les autres réponses ici sont correctes, mais elles ne décrivent pas comment instanceof
fonctionne réellement, ce qui peut intéresser certains avocats spécialistes des langues.
Chaque objet en JavaScript a un prototype, accessible via la propriété __proto__
. Les fonctions ont également une propriété prototype
, qui est le __proto__
initial pour tous les objets créés par elles. Lorsqu'une fonction est créée, un objet unique lui est attribué pour prototype
. L'opérateur instanceof
utilise cette unicité pour vous donner une réponse. Voici à quoi pourrait ressembler instanceof
si vous l’écriviez sous forme de fonction.
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__;
}
}
Ceci est essentiellement une paraphrase de l'ECMA-262 édition 5.1 (également appelée ES5), section 15.3.5.3.
Notez que vous pouvez réaffecter n'importe quel objet à la propriété prototype
d'une fonction, et vous pouvez réaffecter la propriété __proto__
d'un objet après sa construction. Cela vous donnera des résultats intéressants:
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
Je pense qu'il est intéressant de noter que l'instanceof est définie par l'utilisation du mot clé "new" lors de la déclaration de l'objet. Dans l'exemple 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)
Ce qu'il n'a pas mentionné est ceci;
var color1 = String("green");
color1 instanceof String; // returns false
En spécifiant "new", l'état final de la fonction constructeur de chaîne a été copié dans la variable color1, plutôt que de le définir comme valeur de retour. Je pense que cela montre mieux ce que fait le nouveau mot-clé.
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'
L'utilisation de "new" affecte la valeur de "this" à l'intérieur de la fonction à la variable déclarée, tandis que son utilisation n'affecte pas la valeur renvoyée.
Et vous pouvez l'utiliser pour la gestion des erreurs et le débogage, comme ceci:
try{
somefunction();
}
catch(error){
if (error instanceof TypeError) {
// Handle type Error
} else if (error instanceof ReferenceError) {
// Handle ReferenceError
} else {
// Handle all other error types
}
}
Qu'Est-ce que c'est?
Javascript est un langage prototypique, ce qui signifie qu'il utilise des prototypes pour "hériter". l'opérateur instanceof
teste si le type de propriété prototype
d'un constructeur est présent dans la chaîne __proto__
d'un objet. Cela signifie qu'il procédera comme suit (en supposant que testObj est un objet de fonction):
obj instanceof testObj;
obj.__proto__ === testObj.prototype
>> s'il s'agit de true
instanceof
retournera true
.obj.__proto__.__proto__ === testObj.prototype
>> s'il s'agit de true
instanceof
retournera true
.testObj.prototype
, l'opérateur instanceof
retournera false
.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
Quels problèmes cela résout-il?
Cela résolvait le problème de vérifier si un objet dérive d'un certain prototype. Par exemple, quand une fonction reçoit un objet pouvant avoir différents prototypes. Ensuite, avant d'utiliser les méthodes de la chaîne de prototypes, nous pouvons utiliser l'opérateur instanceof
pour vérifier si ces méthodes sont sur l'objet.
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);
Ici, dans la fonction talk()
, on vérifie d'abord si le prototype est situé sur l'objet. Après cela, la méthode appropriée est choisie pour être exécutée. Ne pas effectuer cette vérification peut entraîner l'exécution d'une méthode qui n'existe pas et donc une erreur de référence.
Quand est-ce approprié et quand non?
Nous avons en quelque sorte déjà examiné cela. Utilisez-le lorsque vous avez besoin de vérifier le prototype d'un objet avant de faire quelque chose avec.
//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);
Sur la question "Quand est-ce approprié et quand ne l'est-il pas?", Mes 2 centimes:
instanceof
est rarement utile dans le code de production, mais utile dans les tests dans lesquels vous souhaitez affirmer que votre code renvoie/crée des objets des types corrects. En expliquant les types d'objets que votre code renvoie/crée, vos tests deviennent plus puissants en tant qu'outil de compréhension et de documentation de votre code.
instanceof
n'est qu'un sucre syntaxique pour 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
ne dépend que du prototype d'un constructeur d'objet.
Un constructeur n'est qu'une fonction normale. À proprement parler, il s'agit d'un objet fonction, puisque tout est un objet en Javascript. Et cet objet de fonction a un prototype, car chaque fonction a un prototype.
Un prototype est simplement un objet normal situé dans la chaîne de prototypes d'un autre objet. Cela signifie qu’être dans la chaîne de prototypes d’un autre objet crée un objet pour un prototype:
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
L'opérateur instanceof
devrait être évité car il simule des classes, qui n'existent pas en Javascript. Malgré le mot clé class
, pas plus dans ES2015, car class
n'est qu'une fois de plus un sucre syntaxique pour ... mais c'est une autre histoire.
Je viens de trouver une application réelle et je vais l'utiliser plus souvent maintenant, je pense.
Si vous utilisez des événements jQuery, vous souhaitez parfois écrire une fonction plus générique qui peut également être appelée directement (sans événement). Vous pouvez utiliser instanceof
pour vérifier si le premier paramètre de votre fonction est une instance de jQuery.Event
et réagir correctement.
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
Dans mon cas, la fonction devait calculer quelque chose soit pour tous (via l'événement de clic sur un bouton), soit pour un seul élément spécifique. Le code que j'ai utilisé:
var recalc = function (el) {
el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
// calculate...
};