L'héritage en JavaScript est plutôt étrange. L'héritage d'interface ne peut pas être implémenté et ne peut s'appuyer que sur l'héritage prototypique.
Chaîne prototype
Un prototype est un objet. L'instance créée via le constructeur aura un pointeur pointant vers le prototype pour obtenir les propriétés et méthodes du prototype. De cette façon, l'objet instance a les méthodes d'attribut du constructeur et les méthodes d'attribut du prototype. Pointez ensuite le prototype du constructeur qui doit être hérité sur cette instance, et vous pouvez avoir toutes les méthodes d'attribut de cette instance. obtenir un héritage.
Regardez le code démo ci-dessous :
//声明超类,通过构造函数和原型添加有关属性和方法 function Super(){ this.property = true; } Super.prototype.getSuperValue = function() { return this.property; }; //声明子类的构造函数 function SubType() { this.subproperty = false; } //将子类的原型指向超类的实例,得到超类的一切 SubType.prototype = new Super(); SubType.prototype.constructor = SubType; SubType.prototype.getSubValue = function(){ return this.subproperty; }; //由子类创建对象,测试是否继承超类方法和属性 var instance = new SubType(); console.log(instance.getSuperValue());
Le prototype par défaut de toutes les fonctions est une instance d'Object, donc le prototype par défaut contiendra un pointeur interne pointant vers Object.prototype.
Utilisez instanceof et isPrototypeOf pour déterminer la relation entre le prototype et l'instance :
instance instanceof Object; Object.prototype.isPrototypeOf(instance);
Lorsque vous utilisez la chaîne de prototypes, vous devez définir soigneusement la méthode. Si une sous-classe doit remplacer une méthode ou une extension du supertype, elle doit être placée après l'instruction qui remplace le prototype, afin qu'elle puisse prendre effet. De plus, lors de l'implémentation de l'héritage via la chaîne de prototypes, vous ne pouvez pas utiliser de littéraux d'objet pour créer des méthodes prototypes, qui remplaceront la chaîne de prototypes :
...... SubType.prototype = new Super(); SubType.prototype = { .... };
Cela remplacera le pointeur pointant vers le nouvel objet, réécrivant ainsi la chaîne de prototypes.
La méthode d'héritage de la chaîne de prototypes est défectueuse. Il y a deux problèmes principaux :
1. A partir d'un prototype contenant une valeur de type référence, celle-ci sera partagée par toutes les instances.
Comme mentionné dans l'article précédent, les propriétés du prototype contenant les valeurs du type référence seront partagées par toutes les instances. Si une instance est modifiée, les autres instances changeront en conséquence, les propriétés doivent donc être définies dans le constructeur. Lors de l'héritage via la chaîne de prototypes, que les attributs de la super classe soient définis dans le constructeur ou dans le prototype, ils deviennent tous des objets d'instance et sont hérités par la sous-classe, affectant ainsi les instances de la sous-classe.
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.
L'héritage de la chaîne de prototypes pointe directement le prototype de sous-classe vers l'instance de la superclasse. À ce stade, les paramètres peuvent être transmis à la superclasse. Mais lorsqu'une sous-classe crée une instance, les paramètres ne peuvent être transmis qu'au constructeur de la sous-classe, mais pas au constructeur de la superclasse.
Par conséquent, dans les applications réelles, la chaîne prototype est rarement utilisée seule.
Quelques pratiques de codage associées
Identifier un attribut de prototype
function hasPrototypeProperty(object, name) { return name in object && !object.hasOwnProperty(name); }
Utiliser des objets prototypes dans les constructeurs
function Person(name) { this.name = name; } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name); }, toString: function() { } }; var person1 = new Person('Nicholas'); var person2 = new Person('Greg); console.log(person1 instanceof Person); // true console.log(person1.constructor === Person); // true console.log(person1.constructor === Object); // false console.log(person2 instanceof Person); // true console.log(person2.constructor === Person); // true console.log(person2.constructor === Object); // false
Héritage d'objet
var person1 = { name: 'Nicholas', sayName: function () { console.log(this.name); } }; var person2 = Object.create(person1, { name: { configurable: true, enumerable: true, value: 'Greg', writable: true } }); person1.sayName(); // Nicholas person2.sayName(); // Greg console.log(person1.hasOwnProperty('sayName')); // true console.log(person1.isPropertyOf(person2)); // true console.log(person2.hasOwnProperty('sayName')); // false
Mode Module
var person = (function () { var age = 25; function getAge() { return age; } function growOlder() { age++; } return { name: 'Nicholas', getAge: getAge, growOlder: growOlder }; }());
Constructeur de portée
function Person(name) { this.name = name; } Person.prototype.sayName = function() { console.log(this.name); }; var person1 = Person('Nicholas'); console.log(person1 instanceof Person); // false console.log(typeof person1); // undefined console.log(name); // Nicholas