Maison >interface Web >js tutoriel >Six façons d'implémenter l'héritage en JavaScript

Six façons d'implémenter l'héritage en JavaScript

黄舟
黄舟original
2017-10-23 09:44:211444parcourir

Description de l'héritage en JavaScript :

De nombreux langages orientés objet prennent en charge deux méthodes d'héritage : l'héritage d'interface et l'héritage d'implémentation. L'héritage d'interface hérite uniquement des signatures de méthodes, tandis que l'héritage d'implémentation hérite des méthodes réelles. En JavaScript, l'héritage d'interface ne peut pas être implémenté car la fonction n'a pas de signature, mais seul l'héritage d'implémentation est pris en charge, et l'héritage d'implémentation est principalement obtenu via la chaîne de prototypes.

Tout d'abord, citons la description du document officiel de la chaîne de prototypes : L'idée de base est d'utiliser des prototypes pour permettre à un type de référence d'hériter des propriétés et des méthodes d'un autre type de référence. Pour comprendre ce concept, il faut d'abord clarifier la relation entre constructeurs, prototypes et instances : chaque constructeur (tant qu'il s'agit d'une fonction) possède un attribut prototype, qui pointe vers un objet (cet objet est l'objet prototype du constructeur ); l'objet prototype (Tant qu'il s'agit d'un objet), il existe un attribut constructeur, qui pointe vers un constructeur et l'instance contient un pointeur interne [[Prototype]] pointant vers l'objet prototype ; Pour parler franchement, la construction de la chaîne de prototypes est réalisée en attribuant une instance d'un type au prototype d'un autre constructeur. De cette façon, le sous-type peut accéder à toutes les propriétés et méthodes définies sur le supertype. Chaque objet possède son propre objet prototype, qui utilise l'objet prototype comme modèle pour hériter des propriétés et des méthodes de l'objet prototype. L'objet prototype peut également avoir son propre prototype et en hériter, couche par couche, et ainsi de suite. . La relation est appelée chaîne de prototypes et explique pourquoi un objet a des propriétés et des méthodes définies sur d'autres objets.


Six façons d'implémenter l'héritage en javascript :

Chaîne prototype                                                                                       )


4. Héritage prototypique


5. Héritage parasitaire


6. Héritage combiné parasite (combinaison de l'héritage combiné et de l'héritage parasitaire)


Chaîne prototype

// 实现原型链的一种基本模式
function SuperType(){
            this.property = true;
}
SuperType.prototype.getSuperValue = function(){
            return this.property;
};
function SubType(){
            this.subproperty = false;
}

// 继承,用 SuperType 类型的一个实例来重写 SubType 类型的原型对象
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
            return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue());     // true

PS : SubType hérite de SuperType, et l'héritage est obtenu en créant une instance de SuperType et en attribuant l'instance au prototype de SubType. L'essence de l'implémentation est de remplacer l'objet prototype du sous-type et de le remplacer par une instance du nouveau type. Le nouvel objet prototype du sous-type possède une propriété interne [[Prototype]] qui pointe vers le prototype SuperType et un constructeur de propriété hérité du prototype SuperType qui pointe vers le constructeur SuperType. La chaîne de prototypes finale est la suivante : l'instance pointe vers le prototype de SubType, le prototype de SubType pointe vers le prototype de SuperType et le prototype de SuperType pointe vers le prototype d'Object (le prototype par défaut de toutes les fonctions est une instance d'Object , donc le prototype par défaut contiendra un pointeur interne vers Object.prototype).
Inconvénients de la chaîne de prototypes :
1. Lorsque l'héritage est implémenté via des prototypes, le prototype deviendra en fait une instance d'un autre type. En conséquence, les attributs d'instance d'origine deviennent naturellement les attributs du prototype actuel et seront partagés par toutes les instances. Comprenez ainsi : les propriétés d'instance de la valeur du type référence définie dans le constructeur de supertype deviendront des propriétés de prototype sur le prototype de sous-type et seront partagées par toutes les instances de sous-type.
2. Lors de la création d'une instance d'un sous-type, les paramètres ne peuvent pas être transmis au constructeur du supertype.

2. Emprunter des constructeurs (également appelés faux objets ou héritage classique)

// 在子类型构造函数的内部调用超类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上
function SuperType(){
            // 定义引用类型值属性
            this.colors = ["red","green","blue"];
}
function SubType(){
            // 继承 SuperType,在这里还可以给超类型构造函数传参
            SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("purple");
alert(instance1.colors);     // "red,green,blue,purple"

var instance2 = new SubType();
alert(instance2.colors);     // "red,green,blue"

PS : En utilisant la méthode apply() ou call(), nous sommes en fait le SuperType. Le constructeur est appelé dans le contexte de l’instance SubType à créer. Cela provoque l'exécution de tout le code d'initialisation d'objet défini dans la fonction SuperType() sur le nouvel objet SubType. Par conséquent, chaque instance de SubType aura sa propre copie de la propriété colours.
L'avantage d'emprunter un constructeur est qu'il résout deux problèmes d'héritage d'implémentation de chaîne de prototypes ; l'inconvénient d'emprunter un constructeur est que les méthodes sont toutes définies dans le constructeur, donc la réutilisation des fonctions ne peut pas être réalisée. De plus, les méthodes définies dans le prototype du supertype ne sont pas visibles pour les sous-types, donc tous les types ne peuvent utiliser que le modèle constructeur.

3. Héritage combiné (également appelé héritage pseudo-classique)

// 将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。
function SuperType(name){
            this.name = name;
            this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
            alert(this.name);
};
function SubType(name,age){
            // 借用构造函数方式继承属性
            SuperType.call(this,name);
            this.age = age;
}
// 原型链方式继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
            alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors);      // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("tom",34);
alert(instance2.colors);      // "red,green,blue"
instance2.sayName();
instance2.sayAge();

PS : L'héritage combiné évite les défauts des chaînes de prototypes et des constructeurs empruntés, intègre leurs avantages et devient un standard dans JavaScript Le modèle d'héritage le plus couramment utilisé. De plus, l'utilisation de l'opérateur instanceof et de la méthode isPrototype() peut également être utilisée pour identifier des objets créés sur la base de l'héritage compositionnel. Cependant, il a aussi ses propres défauts. Le plus gros problème est que quelles que soient les circonstances, le constructeur de supertype est appelé deux fois : une fois lors de la création du prototype de sous-type et une fois à l'intérieur du constructeur de sous-type.

4. Héritage prototypique

// 借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
1、自定义一个函数来实现原型式继承
function object(o){
            function F(){}
            F.prototype = o;
            return new F();
}

PS : Dans la fonction object(), créez d'abord un constructeur temporaire, puis utilisez l'objet entrant comme ce constructeur Le prototype du fonction, et renvoie enfin une nouvelle instance de ce type temporaire. Essentiellement, object() effectue une copie superficielle de l'objet qui lui est transmis.
2. Utilisez la méthode Object.create() pour implémenter l'héritage prototypique. Cette méthode accepte deux paramètres : un objet à utiliser comme prototype du nouvel objet et un objet pour définir des propriétés supplémentaires pour le nouvel objet. Cette méthode fonctionne de la même manière que la méthode object() lorsqu'un paramètre est transmis.
Avec le deuxième paramètre transmis, toutes les propriétés spécifiées remplaceront les propriétés du même nom sur l'objet prototype.

var person = {
            name: "luochen",
            colors: ["red","green","blue"]
}; 
var anotherPerson1 = Object.create(person,{
            name: {
                    value: "tom"
            }
});
var anotherPerson2 = Object.create(person,{
            name: {
                    value: "jerry"
            }
});
anotherPerson1.colors.push("purple");
alert(anotherPerson1.name);     // "tom"
alert(anotherPerson2.name);     // "jerry"
alert(anotherPerson1.colors);    // "red,green,blue,purple"
alert(anotherPerson2.colors);    // "red,green,bule,purple";

PS : Si vous souhaitez simplement qu'un objet soit similaire à un autre objet, l'héritage prototypique est tout à fait possible. Mais l'inconvénient est le suivant : les propriétés contenant des valeurs de type référence partagent toujours la valeur correspondante.

5. Héritage parasite

// 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象
function createPerson(original){
            var clone = Object.create(original);   // 通过 Object.create() 函数创建一个新对象
            clone.sayGood = function(){              // 增强这个对象
                        alert("hello world!!!");
            };
            return clone;                                      // 返回这个对象 
}

PS : L'héritage parasite est également un modèle utile lorsque les objets sont principalement considérés à la place des types et des constructeurs personnalisés. L'inconvénient de ce mode est qu'il ne peut pas réutiliser les fonctions.

6. Héritage combinatoire parasite

// 通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
function SuperType(name){
            this.name = name;
            this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
            alert(this.name);
};
function SubType(name,age){
            SuperType.call(this,name);
            this.age = age;
}
// 创建超类型原型的一个副本
var anotherPrototype = Object.create(SuperType.prototype);
// 重设因重写原型而失去的默认的 constructor 属性
anotherPrototype.constructor = SubType;
// 将新创建的对象赋值给子类型的原型
SubType.prototype = anotherPrototype;

SubType.prototype.sayAge = function(){
            alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors);      // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();

var instance2 = new SubType("tom",34);
alert(instance2.colors);      // "red,green,blue"
instance2.sayName();
instance2.sayAge();

PS : La grande efficacité de cet exemple est qu'il n'appelle le constructeur SuperType qu'une seule fois, et évite donc le besoin de SubType.prototype . Créez des attributs inutiles et redondants. Dans le même temps, la chaîne de prototypes reste inchangée ; par conséquent, l'opérateur d'instance et la méthode isPrototype() peuvent être utilisés normalement.

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn