Maison  >  Article  >  interface Web  >  Bases de l'héritage JavaScript (chaîne de prototypes, constructeur emprunté, mode mixte, héritage prototypique, héritage parasitaire, héritage combiné parasite)_compétences javascript

Bases de l'héritage JavaScript (chaîne de prototypes, constructeur emprunté, mode mixte, héritage prototypique, héritage parasitaire, héritage combiné parasite)_compétences javascript

WBOY
WBOYoriginal
2016-05-16 16:39:321394parcourir

J'ai promis d'expliquer l'héritage JavaScript, mais cela a été retardé jusqu'à présent. Sans plus attendre, allons droit au but.

Puisque vous voulez comprendre l'héritage, cela prouve que vous avez déjà une certaine compréhension du JavaScript orienté objet. Si vous ne comprenez toujours rien, vous pouvez vous référer à "Explication de base du JS orienté objet, mode usine, mode constructeur, mode prototype, mode mixte, mode prototype dynamique 》, parlons des méthodes généralement utilisées pour compléter l'héritage JavaScript.

 Chaîne prototype

Le moyen le plus simple d'implémenter l'héritage en JavaScript est d'utiliser la chaîne de prototypes. Pointez simplement le prototype du sous-type vers l'instance du type parent, c'est-à-dire "subtype.prototype = new parent type ();". la méthode de mise en œuvre est la suivante :

// 为父类型创建构造函数
function SuperType() {
  this.name = ['wuyuchang', 'Jack', 'Tim'];
  this.property = true;
}

// 为父类型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 为子类型创建构造函数
function SubType() {
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

// 实现继承的关键步骤,子类型的原型指向父类型的实例
SubType.prototype = new SuperType();

// 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下为测试代码示例 */
var instance1 = new SubType();
instance1.name.push('wyc');
instance1.test.push('h5');
alert(instance1.getSuerperValue());    // true
alert(instance1.getSubValue());      // false
alert(instance1.name);          // wuyuchang,Jack,Tim,wyc
alert(instance1.test);          // h1,h2,h3,h4,h5


var instance2 = new SubType();
alert(instance2.name);          // wuyuchang,Jack,Tim,wyc
alert(instance2.test);          // h1,h2,h3,h4
Vous pouvez voir que le code ci-dessus est un simple héritage implémenté via la chaîne de prototypes, mais il y a encore quelques problèmes dans l'exemple de code de test. Je crois que ceux qui ont lu mon article de blog "

Explication de base du JS orienté objet, mode usine, mode constructeur, mode prototype, mode hybride, mode prototype dynamique" doivent connaître l'existence du code de la chaîne prototypeLe premier problème est que, comme le prototype du sous-type est une instance du type parent, c'est-à-dire les attributs du type parent contenus dans le prototype du sous-type, les attributs du prototype de la valeur du type référence seront être partagé par toutes les instances . L'instance1.name.push('wyc'); du code ci-dessus peut prouver l'existence de ce problème. Le deuxième problème avec la chaîne de prototypes est : Lors de la création d'une instance d'un sous-type, les paramètres ne peuvent pas être transmis au constructeur du supertype. Par conséquent, dans le développement réel, nous utilisons rarement la chaîne de prototypes seule.

 

Emprunter le constructeur

Afin de résoudre les deux problèmes existant dans la chaîne de prototypes, les développeurs ont commencé à utiliser une technique appelée constructeurs empruntés pour résoudre les problèmes existant dans la chaîne de prototypes. L'idée d'implémentation de cette technologie est également assez simple. Il suffit d'appeler le constructeur du type parent au sein du constructeur du sous-type. N'oubliez pas qu'une fonction est juste un objet qui exécute du code dans un environnement spécifique, vous pouvez donc

exécuter un constructeur via la méthode apply() ou call(). Le code est le suivant :

// 为父类型创建构造函数
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

// 为父类型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 为子类型创建构造函数
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

// 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下为测试代码示例 */
var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
// alert(instance1.getSuerperValue());    // error 报错
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
// alert(instance2.getSuerperValue());    // error 报错
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow
Vous pouvez voir que le constructeur du sous-type SubType dans le code ci-dessus réalise l'héritage des attributs en appelant le supertype "SuperType.call(this, name);". Il peut également être utilisé comme parent lors de la création d'une instance. du sous-type. Les paramètres de type sont transmis, mais de nouveaux problèmes surviennent à nouveau. Vous pouvez voir que j'ai défini une méthode dans le constructeur du type parent : testFun, et une méthode dans le prototype du type parent : getSuperValue. Cependant, après que

instancie le sous-type, il est toujours incapable d'appeler la méthode getSuperValue définie dans le prototype du type parent. Il ne peut appeler que la méthode constructeur du type parent : testFun. . Cela revient à utiliser uniquement le modèle de constructeur lors de la création d'objets, ce qui rend la fonction non réutilisable. Compte tenu de ces problèmes, la technique de l’emprunt aux constructeurs est rarement utilisée seule.

Héritage combiné (constructeur emprunté de chaîne de prototypes)

Comme son nom l'indique, l'héritage combiné est un modèle qui combine les avantages de l'utilisation de la chaîne de prototypes et de l'emprunt de constructeurs. L'implémentation est également très simple. Puisqu'il s'agit d'une combinaison, elle combine certainement les avantages des deux parties, c'est-à-dire la méthode d'héritage de la chaîne prototype

et la propriété d'héritage du constructeur . L'implémentation spécifique du code est la suivante :

// 为父类型创建构造函数
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

// 为父类型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 为子类型创建构造函数
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

SubType.prototype = new SuperType();

// 在此处给子类型添加方法,一定要在实现继承之后,否则会在将指针指向父类型的实例,则方法为空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下为测试代码示例 */
var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
alert(instance1.getSuerperValue());      // true
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
alert(instance2.getSuerperValue());      // true
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow
Le code ci-dessus hérite des propriétés du type parent via SuperType.call(this, name); et hérite des méthodes du type parent via SubType.prototype = new SuperType();. Le code ci-dessus résout facilement les problèmes rencontrés par la chaîne de prototypes et les constructeurs empruntés, et est devenu la méthode d'héritage d'instance la plus couramment utilisée en JavaScript. Mais le mode mixte n'est pas sans défauts. Vous pouvez voir que dans le code ci-dessus, lors de l'héritage de la méthode, les propriétés du type parent ont en fait été héritées. Cependant, le type référence est partagé à ce moment, il est donc appelé. deux fois dans le constructeur du sous-type. Le constructeur du type parent hérite des propriétés du type parent et écrase les propriétés héritées du prototype. Il n'est évidemment pas nécessaire d'appeler le constructeur deux fois, mais existe-t-il un moyen de le résoudre ? Examinons les deux modèles suivants pour résoudre ce problème.

Héritage prototype

La méthode d'implémentation de l'héritage prototypique est différente de celle de l'héritage prototypique n'utilise pas de constructeur au sens strict, mais utilise des prototypes pour créer de nouveaux objets basés sur des objets existants sans avoir à les créer. . Le code spécifique est le suivant :

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
Exemple de code :

/* 原型式继承 */
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Tim']
}

var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Bob');

var anotherPerson2 = object(person);
anotherPerson2.name = 'Jack';
anotherPerson2.friends.push('Rose');

alert(person.friends);  // wyc,Nicholas,Tim,Bob,Rose

Héritage parasitaire

/* 寄生式继承 */
function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}
Exemple d'utilisation :

/* 原型式继承 */
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
   
/* 寄生式继承 */
function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Rose']
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

寄生组合式继承

  前面说过了JavaScrip中组合模式实现继承的缺点,现在我们就来解决它的缺点,实现思路是,对于构造函数继承属性,而原型链的混成形式继承方法,即不用在继承方法的时候实例化父类型的构造函数。代码如下:

function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

/* 寄生组合式继承 */
function inheritPrototype(subType, superType) {
  var prototype = object(superType.prototype);
  prototype.constructor = subType;
  subType.prototype = prototype;
}

而在使用时只需要将组合模式中的“SubType.prototype = new SuperType();”这行代码替换成inheritPrototype(subType, superType);即可。寄生组合式继承的高效率体现在它只调用了一次父类型构造函数,避免了创建不必要的或多余的属性。与此同时,原型链还能保持不变,因此,还能够正常使用instanceof和isPrototypeof()。这也是目前来说最理想的继承方式了,目前也在向这种模式转型。(YUI也使用了这种模式。)

此博文参考《JavaScript高级程序设计第3版》,代码为经过改写,更具体,并加了注释使大家更易懂。如对JS继承方面有独到见解的童鞋不别吝啬,回复您的见解供大家参考!

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