Tout d'abord, je vais partager avec vous un exemple d'héritage prototypique JS pour votre référence. Le contenu spécifique est le suivant
1. Héritage du prototype JS
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>JS原型继承</title> </head> <body> <!--原型继承--> <script type="text/javascript"> //clone()函数用来创建新的类Person对象 var clone = function(obj) { var _f = function() {}; //这句是原型式继承最核心的地方,函数的原型对象为对象字面量 _f.prototype = obj; return new _f; } //先声明一个对象字面量 var Animal = { somthing: 'apple', eat: function() { console.log("eat " + this.somthing); } } //不需要定义一个Person的子类,只要执行一次克隆即可 var Cat = clone(Animal); //可以直接获得Person提供的默认值,也可以添加或者修改属性和方法 console.log(Cat.eat()); Cat.somthing = 'orange'; console.log(Cat.eat()); //声明子类,执行一次克隆即可 var Someone = clone(Cat); </script> </body> </html>
2. Comment fonctionne l'héritage prototypique JavaScript
Il est bien connu que JavaScript utilise l'héritage prototypique, mais comme il ne fournit qu'une seule instance d'implémentation par défaut, qui est le nouvel opérateur, son explication est toujours déroutante. Que dois-je expliquer ensuite sur l'héritage prototypique et comment l'utiliser exactement ? en JavaScript.
Définition de l'héritage prototypique
Lorsque vous lirez l'explication sur l'héritage prototypique JS, vous verrez souvent le texte suivant :
Lors de la recherche d'une propriété d'un objet, JavaScript parcourt la chaîne de prototypes jusqu'à trouver une propriété portant un nom donné. ——De JavaScript Jardin secret
La plupart des implémentations de JavaScript utilisent l'attribut __proto__ pour représenter la chaîne de prototypes d'un objet. Dans cet article, nous verrons quelle est la différence entre __proto__ et prototype.
Remarque : __proto__ est une utilisation informelle qui ne doit pas apparaître dans votre code. Elle est uniquement utilisée ici pour expliquer le fonctionnement de l'héritage prototypique JavaScript.
Le code suivant montre comment le moteur JS recherche les attributs :
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined }
Prenons un exemple courant : un point bidimensionnel, de coordonnées bidimensionnelles x y , possède également une méthode d'impression.
En utilisant la définition de l'héritage prototypique que nous avons mentionné précédemment, nous créons un objet Point avec trois propriétés : x, y et print. Afin de créer un nouveau point bidimensionnel, nous devons créer un nouvel objet et laisser son attribut __proto__ pointer vers Point :
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = {x: 10, y: 20, __proto__: Point}; p.print(); // 10 20
L'étrange héritage prototypique de JavaScript
Ce qui est déroutant, c'est que tous ceux qui enseignent l'héritage prototypique ne donneront pas un tel morceau de code, mais donneront le code suivant :
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); p.print(); // 10 20
C'est différent de ce qui a été promis. Ici, Point devient une fonction, puis il y a une propriété prototype, et il y a un nouvel opérateur. Que se passe-t-il avec ce type ?
Comment fonctionne le nouvel opérateur
Le créateur Brendan Eich voulait que JS soit similaire aux langages de programmation orientés objet traditionnels, tels que Java et C++. Dans ces langages, nous utilisons l'opérateur new pour instancier un nouvel objet pour une classe. Il a donc écrit un nouvel opérateur en JS.
C++ a le concept de constructeur utilisé pour initialiser les propriétés d'instance, le nouvel opérateur doit donc cibler les fonctions.
Nous devons placer les méthodes de l'objet au même endroit, et comme nous utilisons un langage prototype, nous le mettons dans l'attribut prototype de la fonction.
L'opérateur new accepte une fonction F et ses arguments : new F(arguments...). Ce processus est divisé en trois étapes :
Créez une instance de la classe. Cette étape consiste à définir l'attribut __proto__ d'un objet vide sur F.prototype.
Initialisez l'instance. La fonction F est appelée avec les arguments transmis et le mot-clé this est défini sur l'instance.
Instance de retour.
Maintenant que nous savons comment fonctionne new, nous pouvons l'implémenter avec du code JS :
function New (f) { var n = { '__proto__': f.prototype }; /*第一步*/ return function () { f.apply(n, arguments); /*第二步*/ return n; /*第三步*/ }; }
Un petit exemple pour regarder son statut professionnel :
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p1 = new Point(10, 20); p1.print(); // 10 20 console.log(p1 instanceof Point); // true var p2 = New (Point)(10, 20); p2.print(); // 10 20 console.log(p2 instanceof Point); // true
Véritable héritage prototypique en JavaScript
La spécification ECMA de JS nous permet uniquement d'utiliser l'opérateur new pour l'héritage prototypique. Mais le grand maître Douglas Crockford a découvert un moyen d'utiliser du nouveau pour obtenir un véritable héritage prototypique ! Il a écrit la fonction Object.create comme suit :
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); };
Cela semble bizarre, mais c'est plutôt sympa : cela crée un nouvel objet et définit son prototype à la valeur que vous souhaitez. Si on autorise l'utilisation de __proto__, alors on peut aussi écrire :
Object.create = function (parent) { return { '__proto__': parent }; };
Le code suivant permet à notre Point d'adopter un véritable héritage prototypique :
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = Object.create(Point); p.x = 10; p.y = 20; p.print(); // 10 20
Conclusion
Nous avons appris ce qu'est l'héritage prototypique JS et comment JS l'implémente d'une manière spécifique. Cependant, l'utilisation d'un véritable héritage prototypique (tel que Object.create et __proto__) présente toujours les inconvénients suivants :
Mauvaise standardisation : __proto__ n'est pas un usage standard, ni même un usage obsolète. Dans le même temps, l'Object.create original et la version originale écrite par Dao Ye sont également différents.
Mauvaise optimisation : Qu'il s'agisse d'Object.create natif ou personnalisé, ses performances sont bien moins optimisées que celles du nouveau, et le premier est jusqu'à 10 fois plus lent que le second.
Ce qui précède représente l’intégralité du contenu de cet article, j’espère qu’il sera utile à l’étude de chacun.