JS的继承方式

Posted by Mars at

几种JS继承方式和优缺点

1、2、3是有构造函数参与的继承,4、5、6是无构造函数参与的单纯对象间的继承。

1. 原型链继承

SubType.prototype = new SuperType();

核心: 子类构造函数的prototype属性,设置为父类的实例。

缺点:

① 所有子类实例的原型,都引用着同一个父类实例A。一旦这个父类实例A上有引用类型属性值obj,一个子类实例修改了这个A.obj,全部子类实例都受到影响。

② 子类实例在创建时,无法给父类构造函数传参。

2. 盗用构造函数

function SubType(){
    SuperType.call(this)
}

核心: 子类构造函数中,用自身的this调用父类构造函数。

缺点:

① 没有实现函数方法的重用,相当于每个子类实例都拥有自己独立的属性和方法;

② 父类原型上的属性和方法,没有被继承。

3. 组合继承

// 借用构造函数,继承父类实例属性
function SubType(){
    SuperType.call(this)
}

// 原型链继承,继承父类原型中的方法
SubType.prototype = new SuperType();

核心: 通过盗用构造函数继承父类实例属性与方法,通过原型链继承父类原型中的方法。

缺点: 调用了两次父类构造函数,效率较差。

4. 原型式继承

Object.create(superTypeInstance)

核心:不通过构造函数,实现两个对象间的继承。

本质上是创建了一个新的对象,它的原型是传入的superTypeInstance,然后返回了这个对象。

与原型链继承是一样的,区别只是是否有构造函数参与。

缺点: 与原型链继承一样,所有子类实例共享同一个原型,互相影响。

5. 寄生式继承

function createObj(superTypeInstance){
// 使用原型式继承对一个父类对象进行继承(创建一个新对象,原型是传入的父类实例)
    let res = Object.create(superTypeInstance)
// 给这个新对象添油加醋,添加自己的属性
    res.say = ()=>{console.log('hi!')}
// 返回新创建的对象
    return res
}

基本还是相当于原型链继承,只不过是在新创建的对象上添加了些自己的属性或方法。

缺点:

① 子类实例共享同一个原型,互相影响;

② 子类中定义的方法,和盗用构造函数一样,没有实现重用。

6. 组合寄生式继承

// 借用构造函数,继承父类实例属性
function SubType(){
    SuperType.call(this)
}

// 寄生式继承,继承父类原型
let prototype = Object.create(SuperType.prototype)
prototype.constructor = SubType
SubType.prototype = prototype

将组合式继承中的父类原型继承方式,从原型链继承(直接将父类实例赋值给子类构造函数prototype属性),更改为寄生式继承(使用父类原型生成新对象,然后添加constructor属性为subtype构造函数)

这样可以少调用一次父类的构造函数。

7. 类继承

使用extends关键字实现,背后仍然是原型链机制(组合寄生式继承)。

Class A extends Class B 的基本原理是这样的,这里可以看出为什么它本质上还是组合寄生式继承:

① A.prototype.[[prototype]] 被设置为 B.prototype;

② A.prototype.constructor 设置为 A本身;

③ A 的 constructor中强制需要调用父类构造函数super(),然后才能正常使用this定义内部属性。

Class本质上还是构造函数。

这里①②两步,对应组合寄生式继承中继承父类原型的操作。③步骤对应在子类中盗用构造函数继承父类实例属性的操作。

Keywords: JavaScript
previousPost nextPost
已经有 1000000 个小伙伴看完了这篇推文。