Maison >interface Web >js tutoriel >Explication détaillée de l'héritage JS
Cette fois, je vais vous apporter une explication détaillée sur l'héritage JS. Quelles sont les précautions lors de l'utilisation de l'héritage JS. Voici des cas pratiques, jetons un coup d'œil.
ECMAScript implémente l'héritage de plusieurs manières. En effet, le mécanisme d'héritage en JavaScript n'est pas explicitement spécifié, mais implémenté par imitation. Cela signifie que tous les détails de l'héritage ne sont pas entièrement gérés par l'interpréteur. Vous pouvez décider de la méthode d'héritage appropriée en fonction de vos besoins.
Usurpation d'identité d'objet
ConstructeurUtilisez ce mot-clé pour attribuer des valeurs à toutes les propriétés et méthodes (c'est-à-dire en utilisant le constructeur méthode de déclaration de classe). Étant donné que le constructeur n'est qu'une fonction, vous pouvez faire du constructeur ClassA une méthode de ClassB, puis l'appeler. ClassB recevra les propriétés et méthodes définies dans le constructeur de ClassA.
function ClassA(name) { this.name = name; this.sayName = function () { console.log(this.name); }; }function ClassB(name,age) { this.classA = ClassA; this.classA(name); delete this.classA; this.age = age; this.sayAge = function(){ console.log(this.age); } }var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25); tom.sayName(); //'Tom'jerry.sayName(); //'Jerry'jerry.sayAge(); //25console.log(tom instanceof ClassA); //trueconsole.log(jerry instanceof ClassA); //falseconsole.log(jerry instanceof ClassB); //true
Toutes les nouvelles propriétés et nouvelles méthodes doivent être définies après avoir supprimé la ligne de code de la nouvelle méthode, car les propriétés et méthodes associées de la super classe peuvent être remplacées.
L'usurpation d'identité d'objet peut réaliser des héritages multiples
Si ClassA et ClassB existent, alors ClassC veut hériter de ces deux classes, comme suit :
function ClassA(name){ this.name = name; this.sayName = function (){ console.log(this.name); } }function ClassB(age){ this.age = age; this.sayAge = function(){ console.log(this.age); } }function ClassC(name,age){ this.method = ClassA; this.method(name); this.method = ClassB; this.method(age); delete this.method; }var tom = new ClassC('Tom',25); tom.sayName(); //'Tom';tom.sayAge(); //25console.log(tom instanceof ClassA); //falseconsole.log(tom instanceof ClassB); //falseconsole.log(tom instanceof ClassC); //true
Le défaut de cette implémentation est : si les deux classes ClassA et ClassB ont des attributs avec le même nom ou la même méthode, ClassB a une priorité élevée car elle hérite de la classe ultérieure.
En raison de la popularité de cette méthode d'héritage, la troisième version d'ECMAScript a ajouté deux méthodes à l'objet Function, à savoir call() et apply().
La méthode d'appel est la plus similaire à la méthode classique d'usurpation d'identité d'objet. Son premier paramètre est utilisé comme objet, et d'autres paramètres sont passés directement à la fonction elle-même
function sayName(prefix) { console.log(prefix + this.name); };var tom = {}; tom.name = "Tom"; sayName.call(tom, 'This is '); //'This is Tom'
La fonction sayName est définie en dehors de l'objet, mais elle peut aussi faire référence à celui-ci.
La méthode d'appel réécrit l'objet pour emprunter l'identité
function ClassA(name){ this.name = name; this.sayName = function(){ console.log(this.name); }}function ClassB(name,age){ //this.method = ClassA; //this.method(name); //delete this.method; ClassA.call(this,name); this.age = age; this.sayAge = function (){ console.log(this.age); }}var tom = new ClassB('Tom',25);tom.sayName(); //'Tom'tom.sayAge(); //25console.log(tom instanceof ClassA); //falseconsole.log(tom instanceof ClassB); //true
La méthode d'appel remplace la manière d'utiliser les attributs pour référencer ClassA.
apply
La méthode apply a deux paramètres, l'objet utilisé comme ceci et les paramètres à passer à la fonction array
function sayName(prefex,mark) { console.log(prefex+ this.name+ mark); };var tom = {}; tom.name = 'Tom'; sayName.apply(tom, ['This is ','!']); //'This is Tom!'
Vous pouvez également utiliser apply pour réécrire l'objet à emprunter l'identité
function ClassA(name){ this.name = name; this.sayName = function(){ console.log(this.name); }}function ClassB(name,age){ ClassA.apply(this,arguments); this.age = age; this.sayAge = function (){ console.log(this.age); }}var tom = new ClassB('Tom',25);tom.sayName(); //'Tom'tom.sayAge(); //25 console.log(tom instanceof ClassA); //falseconsole.log(tom instanceof ClassB); //true
Le tableau de paramètres ne peut être transmis que lorsque l'ordre des paramètres dans la super classe est complètement cohérent avec les paramètres de la sous-classe
Chaîne de prototypes
L'objet prototype est un modèle. Les objets à instancier sont basés sur ce modèle. Tous les attributs et méthodes de l'objet prototype sont transmis à toutes les instances de cette classe. La chaîne de prototypes utilise cette fonction pour implémenter le mécanisme d'héritage.
function ClassA() {}ClassA.prototype.name = 'Tom';ClassA.prototype.sayName = function () { console.log(this.name);};function ClassB() {}ClassB.prototype = new ClassA();var tom = new ClassB();tom.sayName(); //'Tom'console.log(tom instanceof ClassA); //trueconsole.log(tom instanceof ClassB); //true
Ici, l'attribut prototype de ClassB est appelé une instance de ClassA pour éviter d'attribuer les attributs prototypes un par un.
Aucun paramètre n'est défini lors de l'appel de ClassA, car le constructeur doit être sans paramètre dans la chaîne de prototypes.
Dans la chaîne de prototypes, le résultat de instanceof a également changé, renvoyant vrai pour ClassA et ClassB.
En raison de la réaffectation des attributs du prototype, de nouveaux attributs dans la sous-classe doivent apparaître après l'attribution du prototype.
function ClassA() {}ClassA.prototype.name = 'Tom';ClassA.prototype.sayName = function () { console.log(this.name);};function ClassB() {}ClassB.prototype = new ClassA();ClassB.prototype.age = 25;ClassB.prototype.sayAge = function () { console.log(this.age);};var tom = new ClassA();var jerry = new ClassB();tom.sayName(); //'Tom'jerry.sayName(); //'Tom'jerry.name = 'Jerry';tom.sayName(); //'Tom'jerry.sayName(); //'Jerry'jerry.sayAge(); //25console.log(tom instanceof ClassA); //trueconsole.log(jerry instanceof ClassA); //trueconsole.log(jerry instanceof ClassB); //true
Le défaut de la chaîne de prototypes est que l'héritage multiple ne peut pas être réalisé car le prototype de la classe sera réécrit.
Méthode mixte
Le problème avec l'usurpation d'identité d'objet est que la méthode constructeur doit être utilisée et que le constructeur avec paramètres ne peut pas être utilisé lors de l'utilisation de la chaîne de prototypes. Cependant, vous pouvez essayer. pour combiner les deux.
Utilisez des objets pour prétendre hériter des propriétés du constructeur, et utilisez la chaîne de prototypes pour hériter des méthodes du prototype.
function ClassA(name) { this.name = name; } ClassA.prototype.sayName = function () { console.log(this.name); };function ClassB(name, age) { ClassA.call(this, name); this.age = age; } ClassB.prototype = new ClassA(); ClassB.prototype.sayAge = function () { console.log(this.age); };var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);console.log(tom instanceof ClassA); //trueconsole.log(jerry instanceof ClassA); //trueconsole.log(jerry instanceof ClassB); //trueconsole.log(jerry.constructor === ClassA); //trueconsole.log(ClassB.prototype.constructor === ClassA); //true
Dans le constructeur ClassB, l'objet est utilisé pour emprunter l'identité de l'attribut name de ClassA, et la chaîne de prototypes est utilisée pour hériter de la méthode sayName de ClassA. Utilisation de l'héritage de chaîne prototype, instanceof Le mode de fonctionnement est normal.
Mais l'attribut constructeur expose un problème. Chaque objet prototype a un attribut constructeur pointant vers son constructeur, mais le constructeur de l'instance ClassB pointe vers ClassA, ce qui provoquera une confusion dans la chaîne d'héritage. Vous pouvez modifier manuellement le pointeur du constructeur.
function ClassA(name) { this.name = name; } ClassA.prototype.sayName = function () { console.log(this.name); };function ClassB(name, age) { ClassA.call(this, name); this.age = age; } ClassB.prototype = new ClassA(); ClassB.prototype.constructor = ClassB; ClassB.prototype.sayAge = function () { console.log(this.age); };var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);console.log(tom instanceof ClassA); //trueconsole.log(jerry instanceof ClassA); //trueconsole.log(jerry instanceof ClassB); //trueconsole.log(ClassA.constructor === ClassB); //falseconsole.log(jerry.constructor === ClassA); //falseconsole.log(ClassB.prototype.constructor === ClassA); //false
Hériter directement de la chaîne de prototypes
Afin d'économiser de la mémoire, vous ne pouvez pas créer une instance de ClassA et pointer directement le prototype de ClassB vers le prototype de ClassA
function ClassA(name) { this.name = name; } ClassA.prototype.sayName = function () { console.log(this.name); };function ClassB(name, age) { ClassA.call(this, name); this.age = age; } ClassB.prototype = ClassA.prototype; ClassB.prototype.constructor = ClassB; ClassB.prototype.sayAge = function () { console.log(this.age); };var tom = new ClassA('Tom');var jerry = new ClassB('Jerry',25);console.log(ClassA.prototype.hasOwnProperty('sayAge')); //trueconsole.log(ClassA.prototype.constructor === ClassB); //true
Comme ça Le défaut est qu'en raison de la modification directe du pointeur de la chaîne prototype, les attributs de la chaîne prototype ClassB affecteront également ClassA, donc ClassA a la méthode sayAge et l'attribut constructeur de ClassA est ClassB.
Objet vide comme intermédiaire
Pour résoudre les défauts de l'héritage direct de la chaîne de prototypes, un objet vide peut être utilisé comme intermédiaire.
function ClassA(name) { this.name = name; } ClassA.prototype.sayName = function () { console.log(this.name); };function ClassB(name, age) { ClassA.call(this, name); this.age = age; }var fn = function(){}; fn.prototype = ClassA.prototype; ClassB.prototype = new fn(); ClassB.prototype.constructor = ClassB; ClassB.prototype.sayAge = function () { console.log(this.age); };console.log(ClassA.prototype.hasOwnProperty('sayAge')); //falseconsole.log(ClassA.prototype.constructor === ClassB); //false
Bien que l'instance d'objet soit toujours créée, puisque l'objet vide ne prend presque pas de mémoire, la modification du prototype de ClassB n'affectera pas ClassA.
Encapsulé dans la méthode extends
function extends(child,parent){ var fn = function (){}; fn.prototype = parent.prototype; child.prototype = new fn(); child.prototype.constructor = child; child.super = parent.prototype; }
La flexibilité de JS nous permet d'implémenter l'héritage de différentes manières. Comprendre les principes et la mise en œuvre peut nous aider à choisir la méthode appropriée dans différents scénarios. .
Je pense que vous maîtrisez la méthode après avoir lu le cas dans cet article. Pour des informations plus intéressantes, veuillez prêter attention aux autres articles connexes sur le site Web chinois de php !
Lecture recommandée :
Utiliser le code JS pour créer des effets de barrage
Utiliser le canevas H5 pour créer des effets de barrage
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!