JavaScript继承的实现方式

原型链的继承原理

让子类的原型对象指向父类的实例,当子类实例找不到对应的属性和方法时,会沿着原型链往上找。

1
function Parent() {
2
    this.name = ['张三']
3
}
4
5
Parent.prototype.getName = function () {
6
    return this.name
7
}
8
9
function Child() {
10
11
}
12
13
Child.prototype = new Parent()
14
15
Child.prototype.constructor = Child
16
17
const child = new Child()
18
console.log(child.name);                // [张三]
19
console.log(child.getName());           // [张三]
20
21
const child2 = new Child()
22
child2.name[0] = '李四'
23
24
console.log(child.name);                // [李四]
25
console.log(child2.name);               // [李四]

原型链继承的弊端:

  • 原型指向同一个原型实例,当有多个原型指向同一个原型实例时,修改任意一个影响其它的。
  • 没有实现 super 功能。对父类进行传参

构造函数继承

在子类的构造函数中,执行父类的构造函数,并为其绑定子类的this。

1
function Parent(name){
2
    this.name = [name]
3
}
4
5
Parent.prototype.getName = function(){
6
    return this.name
7
}
8
9
Parent.prototype.age = 10;
10
11
function Child (){
12
    Parent.call(this,'李四')  // 可以给父类传参
13
}
14
15
const child = new Child()
16
const child2 = new Child()
17
child2.name[0] = '张三'
18
19
console.log(child.name);            // [李四]
20
console.log(child2.name);           // [张三]
21
console.log(child2.getName());      // child2.getName is not a function
22
console.log(child.age);             // undefined

构造函数继承弊端:

  • 不能继承父类原型上的方法和属性

组合式继承

用原型链实现对原型属性和方法的继承,用借用构造函数继承来实现对实例属性的继承。

1
function Parent(name){
2
    this.name = [name]
3
}
4
5
Parent.prototype.getName = function(){
6
    return this.name
7
}
8
9
Parent.prototype.age = 10;
10
11
function Child (){
12
    Parent.call(this,'李四')
13
}
14
15
Child.prototype = new Parent()
16
Child.prototype.constructor = Child
17
18
const child = new Child()
19
const child2 = new Child()
20
child2.name[0] = '张三'
21
22
console.log(child.name);            // [李四]
23
console.log(child2.name);           // [张三]
24
console.log(child2.getName());      // [张三]
25
console.log(child.age);             // 10

组合式继承弊端:

  • 创建的实例和原型上存在两份相同的属性
  • 调用两次父构造函数,一次是在创建子类型原型时(new Child()),另一次是在子类型构造函数内部(Parent.call)。

寄生式组合继承

1
function Parent(name){
2
    this.name = [name]
3
}
4
5
Parent.prototype.getName = function(){
6
    return this.name
7
}
8
9
Parent.prototype.age = 10;
10
11
function Child (){
12
    Parent.call(this,'李四')
13
}
14
15
// Child.prototype = Parent.prototype   // 给子类的原型添加了 getAge 方法,父类也会增加这个方法
16
Child.prototype = Object.create(Parent.prototype)   // 浅拷贝 防止子类修改原型影响父类
17
Child.prototype.constructor = Child
18
19
Child.prototype.getAge = function(){
20
    console.log(this.age);
21
}
22
23
const child = new Child()
24
const child2 = new Child()
25
const parent = new Parent()
26
27
child2.name[0] = '张三'
28
console.log(child.name);            // [李四]
29
console.log(child2.name);           // [张三]
30
console.log(child2.getName());      // [张三]
31
console.log(child.age);             // 10
32
console.log(parent);