ES6 utilise le mot-clé class pour définir les classes et le mot-clé extends pour hériter des classes. La méthode super doit être appelée dans le constructeur constructeur de la sous-classe pour obtenir l'objet "this" de la classe parent. Lors de l'appel de super, vous pouvez passer des paramètres au constructeur parent. Les sous-classes peuvent utiliser directement les propriétés et les méthodes de la classe parent via le super objet, ou elles peuvent remplacer les définitions de la classe parent via des propriétés ou des méthodes portant le même nom.
class Father { constructor () { this.surname = '王' this.money = Infinity } sayName () { console.log(`My surname is ${this.surname}.`) } } class Son extends Father { constructor (firstname) { super() this.firstname = firstname } sayName () { console.log(`My name is ${super.surname}${this.firstname}.`) } sayMoney () { console.log(`I have ${this.money} money.`) } } let Sephirex = new Son('撕葱') Sephirex.sayName() Sephirex.sayMoney()
Les classes et l'héritage dans ES6 sont essentiellement du sucre syntaxique implémenté à l'aide de prototypes. Les méthodes définies dans la classe sont équivalentes à la définition de méthodes sur le prototype. Définir des propriétés dans la méthode constructeur est équivalent au mode constructeur. super La méthode équivaut à appeler le constructeur de la classe parent dans la sous-classe. Continuons à discuter de la mise en œuvre de l'héritage dans ES5.
Le modèle de base de l'héritage de chaîne de prototypes consiste à laisser l'objet prototype du sous-type pointer vers une instance du type parent, puis à étendre les méthodes pour son prototype.
function Person (name) { this.name = name this.likes = ['apple', 'orange'] } Person.prototype.sayName = function () { console.log(this.name) } function Worker () { this.job = 'worker' } Worker.prototype = new Person() Worker.prototype.sayJob = function () { console.log(this.job) } let Tom = new Worker() let Jerry = new Worker() Tom.likes.push('grape') console.log(Jerry.likes) // [ 'apple', 'orange', 'purple' ]
Principe : Dans l'article précédent, nous avons discuté de __proto__ et de prototype. Il y a un pointeur __proto__ dans l'instance de la sous-classe, qui pointe vers l'objet prototype de son constructeur. Le prototype du constructeur de sous-classe pointe vers une instance de la classe parent, et le __proto__ dans l'instance de la classe parent pointe vers le prototype du constructeur de la classe parent... De cette façon, une chaîne de prototypes est formée.
Il convient de noter que même si l'attribut de type référence dans la classe parent est défini dans le constructeur, il sera toujours partagé par l'instance de classe enfant. En effet, le prototype du constructeur de sous-classe est en fait une instance de la classe parent, donc les propriétés d'instance de la classe parent deviennent naturellement les propriétés du prototype de la sous-classe et les propriétés du prototype des valeurs de type référence sont partagées entre les instances.
Un autre problème avec la chaîne de prototypes est qu'il n'y a aucun moyen de transmettre des paramètres au constructeur de la classe parent sans affecter toutes les instances d'objet. Comme dans l'exemple ci-dessus, lorsque vous utilisez Worker.prototype = new Person() pour pointer le prototype de sous-classe vers l'instance de classe parent, si les paramètres d'initialisation sont transmis, les attributs de nom d'instance de toutes les sous-classes seront les paramètres transmis. Si aucun paramètre n’est transmis ici, il n’y aura aucun moyen de transmettre ultérieurement des paramètres au constructeur de la classe parent. Par conséquent, le modèle d’héritage de chaîne prototype est rarement utilisé seul.
Les constructeurs emprunteurs peuvent résoudre le problème des attributs de type référence partagés. Ce qu'on appelle "emprunter" un constructeur consiste à appeler le constructeur de la classe parent dans le constructeur de la sous-classe - n'oubliez pas que le but de ceci dans la fonction n'a rien à voir avec l'endroit où la fonction est définie, mais seulement avec l'endroit où il est appelé. Nous pouvons utiliser call ou apply pour appeler le constructeur de la classe parent sur l'instance de sous-classe afin d'obtenir les propriétés et les méthodes de la classe parent, de la même manière que l'appel de la super méthode dans le constructeur de sous-classe ES6.
function Person (name) { this.name = name this.likes = ['apple', 'orange'] } function Worker (name) { Person.call(this, name) this.job = 'worker' } let Tom = new Worker('Tom') Tom.likes.push("grape") let Jerry = new Worker('Jerry') console.log(Tom.likes) // [ 'apple', 'orange', 'grape' ] console.log(Jerry.likes) // [ 'apple', 'orange' ]
Le problème avec la simple utilisation du constructeur est que la fonction ne peut pas être réutilisée et que la sous-classe ne peut pas obtenir les attributs et les méthodes sur le prototype de la classe parent.
L'héritage combiné emprunte des constructeurs pour définir les propriétés de l'instance et utilise des méthodes de partage de chaîne de prototypes. La combinaison de l'héritage combine le mode chaîne de prototypes et le constructeur emprunté, exploitant ainsi les points forts des deux et compensant leurs défauts respectifs. Il s'agit du mode d'héritage le plus couramment utilisé dans js.
function Person (name) { this.name = name this.likes = ['apple', 'orange'] } Person.prototype.sayName = function () { console.log(this.name) } function Worker (name, job) { Person.call(this, name) // 第二次调用 Person() this.job = job } Worker.prototype = new Person() // 第一次调用 Person() Worker.prototype.constructor = Worker Worker.prototype.sayJob = function () { console.log(this.job) } let Tom = new Worker('Tom', 'electrician') Tom.likes.push('grape') console.log(Tom.likes) // [ 'apple', 'orange', 'grape' ] Tom.sayName() // Tom Tom.sayJob() // electrician let Jerry = new Worker('Jerry', 'woodworker') console.log(Jerry.likes) // [ 'apple', 'orange' ] Jerry.sayName() // Jerry Jerry.sayJob() // woodworker
L'héritage combiné n'est pas sans inconvénients, c'est-à-dire que le processus d'héritage appellera deux fois le constructeur de la classe parent. Lorsque le constructeur Person est appelé pour la première fois, Worker.prototype obtiendra deux attributs : name et likes ; lorsque le constructeur Worker est appelé, le constructeur Person sera appelé à nouveau, et cette fois les attributs d'instance name et likes sont directement créés. , couvrant deux propriétés portant le même nom dans le prototype.
La fonction objet suivante a été enregistrée dans un article de Douglas Crockford. À l'intérieur de la fonction objet, un constructeur temporaire est d'abord créé, puis l'objet transmis est utilisé comme prototype de ce constructeur, et enfin une nouvelle instance de ce type temporaire est renvoyée. Essentiellement, object() effectue une copie superficielle de l'objet qui lui est transmis. Cette méthode d'héritage équivaut à copier les propriétés et méthodes du type parent vers le sous-type, puis à ajouter les propriétés et méthodes respectives au sous-type.
Cette méthode partagera également les propriétés des valeurs de type référence.
function object(o){ function F(){} F.prototype = o; return new F(); } let Superhero = { name: 'Avenger', skills: [], sayName: function () { console.log(this.name) } } let IronMan = object(Superhero) IronMan.name = 'Tony Stark' IronMan.skills.push('fly') let CaptainAmerica = object(Superhero) CaptainAmerica.name = 'Steve Rogers' CaptainAmerica.skills.push('shield') IronMan.sayName() // Tony Stark console.log(IronMan.skills) // [ 'fly', 'shield' ]
ES5 utilise la méthode Object.create() pour standardiser l'héritage prototypique. Cette méthode accepte deux paramètres : un objet à utiliser comme prototype du nouvel objet et (éventuellement) un objet pour définir des propriétés supplémentaires pour le nouvel objet. Object.create() se comporte de la même manière que la méthode object() lorsqu'un argument est transmis. Le deuxième paramètre de la méthode Object.create() a le même format que le deuxième paramètre de la méthode Object.defineProperties().
let CaptainAmerica = Object.create(Superhero, { name: { value: 'Steve Rogers', configurable: false } })
L'héritage parasite est facile à comprendre. Il s'agit simplement d'une fonction d'usine qui encapsule le processus d'héritage. Les méthodes étant définies directement sur l'objet, les méthodes ajoutées par héritage parasite ne peuvent pas être réutilisées.
function inherit(parent){ var clone = Object.create(parent) clone.name = 'hulk' clone.sayHi = function(){ console.log("hi") } return clone } let Hulk = inherit(Superhero) Hulk.sayName() // hulk Hulk.sayHi() // hi
Comme mentionné précédemment, l'héritage combiné est la méthode d'héritage la plus couramment utilisée en js, mais l'inconvénient est que le constructeur de la classe parent sera appelé deux fois . L'héritage compositionnel parasite peut résoudre ce problème et est considéré comme la méthode d'héritage la plus idéale pour les objets contenant des valeurs de type référence.
L'idée de base de l'héritage combiné parasite est qu'il n'est pas nécessaire d'appeler le constructeur de la classe parent pour spécifier le prototype de la sous-classe. Il suffit d'une copie du prototype de la classe parent. . L'héritage compositionnel parasite consiste à hériter de propriétés en empruntant des constructeurs, puis à utiliser l'héritage parasitaire pour hériter du prototype de la classe parent.
function inheritPrototype(subType, superType){ var prototype = Object.create(superType.prototype) prototype.constructor = subType subType.prototype = prototype } function Person (name) { this.name = name this.likes = ['apple', 'orange'] } Person.prototype.sayName = function () { console.log(this.name) } function Worker (name, job) { Person.call(this, name) this.job = job } inheritPrototype(Worker, Person) Worker.prototype.sayJob = function () { console.log(this.job) }
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!