Ok, jouons à un petit jeu d'esprit :
De l'image ci-dessus nous pouvons voir :
- Lorsque nous créons une fonction comme
function Foo() {}
JavaScript crée un Function
instance.
- Chaque
Function
(la fonction constructeur) possède une propriété prototype
qui est un pointeur.
- El
prototype
de la fonction constructeur pointe vers son objet prototype.
- L'objet prototype possède une propriété
constructor
qui est également un pointeur.
- El
constructor
de l'objet prototype renvoie à sa fonction de construction.
- Lorsque nous créons une nouvelle instance de
Foo
comme new Foo()
JavaScript crée un nouvel objet.
- L'interne
[[proto]]
de l'instance pointe vers le prototype du constructeur.
Maintenant, la question se pose de savoir pourquoi JavaScript n'attache pas l'élément constructor
à l'objet d'instance au lieu du prototype. Pensez-y :
function defclass(prototype) {
var constructor = prototype.constructor;
constructor.prototype = prototype;
return constructor;
}
var Square = defclass({
constructor: function (side) {
this.side = side;
},
area: function () {
return this.side * this.side;
}
});
var square = new Square(10);
alert(square.area()); // 100
Comme vous pouvez le constater, le constructor
est simplement une autre méthode du prototype, comme la propriété area
dans l'exemple ci-dessus. Ce qui fait que le constructor
La particularité de cette propriété est qu'elle est utilisée pour initialiser une instance du prototype. Sinon, c'est exactement la même chose que n'importe quelle autre méthode du prototype.
Définir le constructor
sur le prototype est avantageux pour les raisons suivantes :
- C'est logiquement correct. Par exemple, considérez
Object.prototype
. Le site constructor
propriété de Object.prototype
Les points suivants Object
. Si le constructor
a été définie sur l'instance, alors Object.prototype.constructor
serait undefined
parce que Object.prototype
est une instance de null
.
- Elle n'est pas traitée différemment des autres méthodes de prototypage. Cela rend le travail de
new
plus facile, puisqu'il n'est pas nécessaire de définir l'option constructor
sur chaque instance.
- Chaque instance partage le même
constructor
propriété. D'où son efficacité.
Maintenant, lorsque nous parlons d'héritage, nous avons le scénario suivant :
De l'image ci-dessus nous pouvons voir :
- Le constructeur dérivé
prototype
est définie comme l'instance du constructeur de base.
- Ainsi, l'interne
[[proto]]
de l'instance du constructeur dérivé pointe également vers lui.
- Ainsi, le
constructor
de l'instance du constructeur dérivé pointe maintenant vers le constructeur de base.
Quant à la instanceof
contrairement à ce que l'on croit, il ne dépend pas de l'opérateur constructor
de l'instance. Comme nous pouvons le voir ci-dessus, cela conduirait à des résultats erronés.
El instanceof
est un opérateur binaire (il a deux opérandes). Il opère sur un objet instance et une fonction constructeur. Comme expliqué sur Réseau de développeurs Mozilla il fait simplement ce qui suit :
function instanceOf(object, constructor) {
while (object != null) {
if (object == constructor.prototype) { //object is instanceof constructor
return true;
} else if (typeof object == 'xml') { //workaround for XML objects
return constructor.prototype == XML.prototype;
}
object = object.__proto__; //traverse the prototype chain
}
return false; //object is not instanceof constructor
}
Pour le dire simplement, si Foo
hérite de Bar
alors la chaîne du prototype de l'instance de Foo
serait :
foo.__proto__ === Foo.prototype
foo.__proto__.__proto__ === Bar.prototype
foo.__proto__.__proto__.__proto__ === Object.prototype
foo.__proto__.__proto__.__proto__.__proto__ === null
Comme vous pouvez le constater, chaque objet hérite de l'objet Object
Constructeur. La chaîne de prototypes se termine lorsqu'un constructeur interne [[proto]]
indique que la propriété null
.
El instanceof
parcourt simplement la chaîne de prototypes de l'objet d'instance (le premier opérande) et compare la chaîne interne [[proto]]
de chaque objet à la propriété prototype
de la fonction constructeur (le second opérande). S'ils correspondent, il retourne true
; et sinon, si la chaîne de prototypes se termine, il retourne false
.