Home  >  Article  >  Web Front-end  >  In-depth understanding of the six inheritance methods of JavaScript (picture and text)

In-depth understanding of the six inheritance methods of JavaScript (picture and text)

黄舟
黄舟Original
2017-03-24 14:44:191011browse

This article will lead everyone to re-understand the six inheritance methods of JavaScript. It is very good and has reference value. Friends in need can refer to it

Class inheritance (Constructor)

There is actually no concept of classes in JS, and so-called classes are also simulated. Especially when we use the new keyword, the concept of "class" becomes more like classes in other languages. Class inheritance is to call the constructor of the parent class within the function object so that it can obtain the methods and properties of the parent class. The call and apply methods provide support for class inheritance. By changing the action environment of this, the subclass itself has various attributes of the parent class.

var father = function() {
this.age = 52;
this.say = function() {
alert('hello i am '+ this.name ' and i am '+this.age + 'years old');
}
}
var child = function() {
this.name = 'bill';
father.call(this);
}
var man = new child();
man.say();

Prototypal inheritance

Prototypal inheritance is often used in development. It is different from class inheritance because inheritance is not in the object itself, but in the prototype of the object (prototype). Every object has a prototype, which is reflected in a hidden proto attribute in the browser. In some modern browsers you can change them. For example, in zepto, by adding zepto's fn object to the proto attribute of an empty array, the array becomes a zepto object and has all methods. Having said that, when an object needs to call a method, it goes back to the nearest prototype to find the method. If it is not found, it will continue searching downwards again. In this way, I searched step by step until I found the method I was looking for. These looked-up prototypes form the object's prototype chain. The prototype finally points to null. What we call prototypal inheritance is to transfer the methods of the parent object to the prototype of the child class. These methods and properties are not available in the constructor of subclasses.

var father = function() {
}
father.prototype.a = function() {
}
var child = function(){}
//开始继承
child.prototype = new father();
var man = new child();
man.a();

You can see that prototypal inheritance is implemented in the seventh line. Many people are familiar with this approach. By printing man in the browser we can check the inheritance relationship of each prototype.

You can see the hierarchical relationship child->object (the object instantiated by father)->father. The child inherits the things on the father's prototype through the middle layer. But why is there a layer of object in the middle? Why not set child.prototype = father.prototype. The answer is that if you do this, there will be no difference between child and father. You should still remember that there is a constructor attribute in prototype, which points to the constructor. Under normal circumstances, we need to change the value of the constructor back to point to the child's constructor. But if father.prototype is directly assigned to child.prototype, who should the constructor point to? So it is obvious that child and father can only be maintained as independent objects through the middle layer.

Comparison between class inheritance and prototypal inheritance

Constructor (class) inheritance

First of all, the methods inherited from the constructor will be stored in the parent object. Each instance will save the funciton in the memory. This approach is not expected to cause performance problems.

Secondly, class inheritance is immutable. It cannot be reused. During runtime, it cannot modify or add new methods. This method is a dead method that is self-contained. In practice, it is rarely used simply.

Prototypal inheritance

Advantages:

The prototype chain can be changed: the parent class on the prototype chain can be replaced and extended

Subclasses can be modified by changing the prototype link. In addition, class inheritance does not support multiple inheritance, but for prototypal inheritance, you only need to write extend to extend the object.

But prototype chain inheritance also has two problems.

First, the prototype attribute containing the reference type value will be shared by all instances (it can be understood this way: execute sub1.arr.push(2); first perform an attribute search on sub1 and find I searched through the instance attributes (there were no instance attributes in this example) and couldn't find it, so I started looking up the prototype chain and got the prototype object of sub1. I searched and found that there was an arr attribute, so I inserted 2 at the end of arr. sub2.arr has also changed).

Second, when creating an instance of a subtype, parameters cannot be passed to the constructor of the supertype. (In fact, it should be said that there is no way to pass parameters to a supertype's constructor without affecting all object instances.) In practice, pure prototype chaining is rarely used.

function Super(){
this.val = 1;
this.arr = [1];
}
function Sub(){
// ...
}
Sub.prototype = new Super(); // 核心
var sub1 = new Sub();
var sub2 = new Sub();
sub1.val = 2;
sub1.arr.push(2);
alert(sub1.val); // 2
alert(sub2.val); // 1
alert(sub1.arr); // 1, 2
alert(sub2.arr); // 1, 2

Summary:

When instantiating class inheritance, the parent class can pass parameters and cannot be reused (the parent class is immutable, Each instance will save the parent class content in memory)

原型继承在实例化时,父类不可传参,可以复用(原型链可改变(父类可替换可扩展),父类不会保存在内存中,而是顺着原型链查找,但是结果是原型属性会被所有实例共享(尤其影响引用类型值))

组合继承(最常用)

组合继承将原型链和借用构造函数的技术结合到一起,发挥两者之长的一种继承模式。

思路是使用原型链实现对原型属性和方法的继承,通过借用构造函数实现对实例属性的继承。

function SuperType(name){
this.name = name;
this.numbers = [1,2,3];
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var instance1 = new SubType('aaa',21);
instance1.numbers.push(666);
console.log(instance1.numbers);
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType('bbb',22);
console.log(instance2.numbers);
instance2.sayName();
instance2.sayAge();

把实例函数都放在原型对象上,通过Sub.prototype = new Super();继承父类函数,以实现函数复用。

保留借用构造函数方式的优点,通过Super.call(this);继承父类的基本属性和引用属性,以实现传参;

优缺点

优点:

  1. 可传参

  2. 函数可复用

  3. 不存在引用属性共享问题(图纸)

缺点:

(一点小瑕疵)子类原型上有一份多余的父类实例属性,因为父类构造函数被调用了两次,生成了两份,而子类实例上的那一份屏蔽了子类原型上的。。。又是内存浪费,比刚才情况好点,不过确实是瑕疵。

The above is the detailed content of In-depth understanding of the six inheritance methods of JavaScript (picture and text). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn