Maison > Article > interface Web > Vous faire comprendre l'héritage JavaScript en dix minutes
Cet article vous apporte des connaissances pertinentes sur l'héritage en JavaScript, y compris l'héritage de chaîne de prototypes, l'héritage de constructeur emprunté, l'héritage combiné et l'héritage multiple. J'espère qu'il vous sera utile.
Héritage de la chaîne de prototypes
Principe
L'essence est de réécrire l'objet prototype et de le remplacer par une instance d'un nouveau type. Dans le code suivant, les propriétés et méthodes qui existaient à l'origine dans l'objet instance SuperType existent désormais également dans SubType.prototype.
Implementation
function Super(){ this.value = true; } Super.prototype.getValue = function(){ return this.value } function Sub(){}; // Sub继承了Super Sub.prototype = new Super(); Sub.prototype.constructor = Sub; const ins = new Sub(); console.log(ins.getValue()); // true
Sub hérite de Super, et l'héritage est obtenu en créant une instance Super et en attribuant l'instance à Sub.prototype. Toutes les propriétés et méthodes qui existaient à l'origine dans l'instance de Super existent désormais également dans Sub.prototype. Comme le montre l'image.
Comme vous pouvez le voir sur l'image ci-dessus, le prototype fourni par Sub par défaut n'est pas utilisé, mais un nouveau prototype lui est donné, ce nouveau prototype est une instance de Super ; Ainsi, le nouveau prototype possède non seulement les propriétés et les méthodes d'une instance de Super, mais il pointe également vers le prototype de Super. Le résultat final est le suivant : la méthode
ins=>Sub的原型=>Super的原型
getValue() est toujours dans Sub.prototype, mais l'attribut value est dans Sub.prototype. En effet, value est une propriété d'instance et getValue() est une méthode prototype. Puisque Sub.prototype est désormais une instance de Super, la valeur se trouve dans cette instance.
De plus, veuillez noter que ins.constructor pointe désormais vers Super. C'est parce que le constructeur d'origine dans Sub.prototype a été réécrit.
Inconvénients
Les propriétés du prototype privé seront partagées par les instances
Lors de la création d'une instance d'un sous-type, les paramètres ne peuvent pas être transmis au constructeur du type parent
Le principal problème avec la chaîne de prototypes héritage : les propriétés privées du prototype sont partagées par les instances, c'est pourquoi les propriétés sont définies dans le constructeur plutôt que dans l'objet prototype. Lorsque l'héritage est implémenté via des prototypes, l'instance du prototype devient une instance d'une autre classe. Par conséquent, les attributs de l’instance d’origine sont naturellement devenus les attributs du prototype actuel.
function Super(){ this.colors = ['red','green','blue']; } Super.prototype.getValue = function(){ return this.colors } function Sub(){}; //Sub继承了Super Sub.prototype = new Super(); const ins1 = new Super(); ins1.colors.push('black'); console.log(ins1.colors);//['red','green','blue','black']; const ins2 = new Sub(); console.log(ins2.colors);//['red','green','blue','black'];
Le deuxième problème avec la chaîne de prototypes est que lors de la création d'une instance d'un sous-type, les paramètres ne peuvent pas être transmis au constructeur du type parent. En fait, il faut dire qu'il n'existe aucun moyen de passer des paramètres au constructeur du type parent sans affecter toutes les instances. Couplé au problème selon lequel les propriétés des prototypes contenant des valeurs de type de référence seront partagées par toutes les instances, dans la pratique, l'héritage de chaîne de prototypes est rarement utilisé seul
Problèmes d'attention
Utilisez les méthodes d'héritage de chaîne de prototypes pour définir soigneusement les méthodes et les sous-types. Parfois, vous devez remplacer une méthode de la classe parent ou ajouter une méthode qui n'existe pas dans la classe parent. Quoi qu’il en soit, le code qui ajoute des méthodes au prototype doit être placé après l’instruction qui remplace le prototype.
function Super() { this.colors = ['red', 'green', 'blue']; } Super.prototype.getValue = function() { return this.colors } function Sub() { this.colors = ['black']; }; //Sub继承了Super Sub.prototype = new Super(); //添加父类已存在的方法,会重写父类的方法 Sub.prototype.getValue = function() { return this.colors; } //添加父类不存在的方法 Sub.prototype.getSubValue = function(){ return false; } const ins = new Sub(); //重写父类的方法之后得到的结果 console.log(ins.getValue()); //['black'] //在子类中新定义的方法得到的结果 console.log(ins.getSubValue());//false //父类调用getValue()方法还是原来的值 console.log(new Super().getValue());//['red', 'green', 'blue']
Héritage de constructeur emprunté
Principe
Constructeur emprunté (parfois aussi appelé héritage de pseudo-classe ou héritage classique). L'idée de base de cette technique est assez simple, elle consiste à appeler le constructeur de la classe parent à l'intérieur du constructeur de la classe enfant. N'oubliez pas que les fonctions ne sont rien d'autre que des objets qui exécutent du code dans un environnement spécifique, les constructeurs peuvent donc également être exécutés sur des objets nouvellement créés en utilisant les méthodes apply() et call().
Implémentation
function Super() { this.colors = ['red', 'green', 'blue']; } Super.prototype.getValue = function(){ return this.colors; } function Sub(){ //继承了Super Super.call(this);//相当于把构造函数Super中的this替换成了ins实例对象,这样在Super只有定义的私有属性会被继承下来,原型属性中定义的公共方法不会被继承下来 } const ins = new Sub(); console.log(ins.colors);
Passage des paramètres : par rapport à la chaîne de prototypes, l'héritage du constructeur d'emprunt présente un grand avantage, c'est-à-dire que vous pouvez transmettre des paramètres au constructeur de la classe parent dans le constructeur de la sous-classe
function B(name){ this.name = name; } function A(){ //继承了B,同时还传递了参数 B.call(this,'ZZ'); //实例属性 this.age = 100; } const p = new A(); alert(p.name);//'ZZ' alert(p.age);//100
Inconvénients
Si vous empruntez simplement le constructeur, vous ne pourrez pas éviter les problèmes du modèle de constructeur - les méthodes sont toutes définies dans le constructeur, donc la réutilisation des fonctions est hors de question. De plus, les méthodes définies dans le prototype de la classe parent ne sont pas visibles par la sous-classe, cette méthode est donc rarement utilisée.
Héritage combiné
Principe
L'héritage combiné fait référence à un modèle d'héritage qui combine le chaînage de prototypes et la technologie de constructeur empruntée pour tirer parti du meilleur des deux. L'idée derrière cela est d'utiliser la chaîne de prototypes pour hériter des propriétés et méthodes publiques du prototype, et d'hériter des propriétés privées de la classe parent en empruntant l'héritage du constructeur. De cette manière, la réutilisation des fonctions est obtenue en définissant des méthodes sur le prototype de la classe parent, et chaque instance est garantie d'avoir les propriétés privées de la classe parent.
Réalisé
function Super(name){ this.name = name; this.colors = ['red','blue','green']; } Super.prototype.sayName = function(){ alert(this.name); } function Sub(name,age){ Super.call(this,name); this.age = age; } // 继承方法 Sub.prototype = new Super(); Sub.prototype.constructor = Sub; Sub.prototype.sayAge = function(){ alert(this.age); } const ins = new Sub('jarvis',18); ins.colors.push('black'); console.log(ins.colors);// ["red", "blue", "green", "black"] ins.sayName();//'jarvis' ins.sayAge();//18 const ins2 = new Sub('ershiyi',21); console.log(ins2.colors);//["red", "blue", "green"] ins2.sayName();//'ershiyi' ins2.sayAge();//21
在上个例子中,Sub构造函数定义了两个属性:name和age。Super的原型定义了一个sayName()方法。在Sub构造函数中调用Super构造函数时传入了name参数,紧接着又定义它自己的属性age。然后,将Super的实例赋值给Sub的原型,然后又在该新原型上定义了方法sayAge()。这样一来,就可以让不同的Sub实例分别拥有自己的属性——包括colors属性,又可以使用相同的方法组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,称为JavaScript中最常用的继承模式。
缺点
无论在什么情况下,都会调用两次父类的构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数内部。
寄生组合式继承
原理
组合继承是JavaScript最常用的继承模式;不过,它也有自己的不足。组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数:一次是在创建子类原型的时候,另一次是在子类构造函数内部。没错,子类型最终会包含超类型对象的全部实例属性,但不得不在调用子类型构造函数时重写这些属性。再来看一看下面组合继承的例子。
实现
function Super(name){ this.name = name; this.colors = ['red','blue','green']; } Super.prototype.sayName = function(){ alert(this.name); } function Sub(name,age){ Super.call(this,name); this.age = age; } // 继承方法 Sub.prototype = new Super(); Sub.prototype.constructor = Sub; Sub.prototype.sayAge = function(){ alert(this.age); } const ins = new Sub('jarvis',18); ins.colors.push('black'); console.log(ins.colors);// ["red", "blue", "green", "black"] ins.sayName();//'jarvis' ins.sayAge();//18 const ins2 = new Sub('ershiyi',21); console.log(ins2.colors);//["red", "blue", "green"] ins2.sayName();//'ershiyi' ins2.sayAge();//21
所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背 后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。寄生组合式继承的基本模式如下所示。
function Super(name){ this.name = name; this.colors = ['red','blue','green']; } Super.prototype.sayName = function(){ alert(this.name); } function Sub(name,age){ //继承实例属性 Super.call(this,name); this.age = age; } // 继承公有的方法 Sub.prototype = Object.create(Super.prototype); Sub.prototype.constructor = Sub; Sub.prototype.sayAge = function(){ alert(this.age); } const ins = new Sub('jarvis',18); ins.colors.push('black'); console.log(ins.colors);// ["red", "blue", "green", "black"] ins.sayName();//'jarvis' ins.sayAge();//18 const ins2 = new Sub('ershiyi',21); console.log(ins2.colors);//["red", "blue", "green"] ins2.sayName();//'ershiyi' ins2.sayAge();//21
多重继承
JavaScript中不存在多重继承,那也就意味着一个对象不能同时继承多个对象,但是可以通过变通方法来实现。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>18 多重继承</title> </head> <body> <script type="text/javascript"> // 多重继承:一个对象同时继承多个对象 // Person Parent Me function Person(){ this.name = 'Person'; } Person.prototype.sayName = function(){ console.log(this.name); } // 定制Parent function Parent(){ this.age = 30; } Parent.prototype.sayAge = function(){ console.log(this.age); } function Me(){ // 继承Person的属性 Person.call(this); Parent.call(this); } // 继承Person的方法 Me.prototype = Object.create(Person.prototype); // 不能重写原型对象来实现 另一个对象的继承 // Me.prototype = Object.create(Parent.prototype); // Object.assign(targetObj,copyObj) Object.assign(Me.prototype,Parent.prototype); // 指定构造函数 Me.prototype.constructor = Me; const me = new Me(); </script> </body> </html>
ES5 与 ES6 继承差异
在 ES5 的传统继承中, this 的值会先被派生类创建,随后基类构造器才被调用。这意味着 this 一开始就是派生类的实例,之
后才使用了基类的附加属性对其进行了装饰。
在 ES6 基于类的继承中, this 的值会先被基类创建,随后才被派生类的构造 器所修改。结果是 this 初始就拥有作为基类的内置对象的所有功能,并能正确接收与之关联的所有功能。
【相关推荐:javascript学习教程】
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!