JS中的三种继承模式(原型链继承、借用构造函数继承、组合继承及ES6中class的实现原理)
发布日期:2021-05-12 21:17:51 浏览次数:25 分类:精选文章

本文共 1814 字,大约阅读时间需要 6 分钟。

JS中的三种继承模式

写在前面:如果此篇博客中有任何错误的地方,欢迎大家的指正!让我们共同进步!

如果觉得这篇博客有用就点赞+收藏+关注三连吧!


JS中的继承模式大体分为三种:

①原型链继承
②借用构造函数继承
③组合继承

接下来让我们逐个的对其进行剖析。

在这里插入图片描述


方式一、继承模式-原型链继承

在这里插入图片描述
在这里插入图片描述在这里插入图片描述
为了更好的理解为什么要这样做,我们来看一看这样做的图示:
在这里插入图片描述
代码核心思路:
通过将子类型的原型赋为父类型的一个实例对象,使得在创建子类的实例对象的时候可以逐步通过__proto__属性(隐式原型链)查找到父类的方法。

注意:

由于把子类型的prototype指向了另外一个对象,因此要注意子类型的方法要在继承后在写入,防止添加到普通的空Object实例对象后,由于指向重置,使其变为垃圾对象,从而丢失子类型自己的方法。


弊端思考:

这样就使得子类的实例也可以调用父类的方法啦!
但是仔细观察一下这个图示,相信悉心的同学已经发现了一个Bug。

①如果我们这样输出:

在这里插入图片描述
②其输出结果为:Supper()
在这里插入图片描述
③为了寻找这个问题的原因,我们直接打印输出sub对象。
在这里插入图片描述
④输出结果如下:
在这里插入图片描述我们发现果然是通过Suppuer的原型对象的constructor才找到的Supper,这显然是错误的。

图示理解如下:我们通过sub调用constructor,实际是从原型链依次查找,最终只在Supper的Prototype中查找到的constructor,因此指向的是Supper()。

在这里插入图片描述
解决方法重新定向Sub.prototype.constructor = Sub;(代码的38句)
在这里插入图片描述
如此即可将这个bug消除。


方法二、继承模式-借用构造函数继承

在这里插入图片描述
接下来我们通过实例来进行演示。
在这里插入图片描述

执行结果如下:

在这里插入图片描述
(注:此方法实质上是一种假继承,强行调用父类的构造函数,从而为子类添加属性,这里面其实没有继承,只是简化代码罢了。)

通过整合第一种方法和第二种方法的思路,进而有了第三个方法——组合继承。


方式三、继承模式-组合继承

组合的方法分为两步

①利用原型链实现对父类型对象的方法继承
②利用call()借用父类的构造函数初始化相同的属性

接下来让我们看一个实例。

在这里插入图片描述在这里插入图片描述

执行结果如下:
在这里插入图片描述
这种方法的好处:
①对于属性:继承于父类的属性,单独存储在子类型实例对象中,因此每个实例对象的属性互不影响。
②对于方法:方法则是通过原型链进行查找调用,在执行过程中通过this进行属性的动态绑定,因此不会在堆内存中占用多余的空间。

但是在实际代码书写时,这样constructor也会被for…in遍历到,

在这里插入图片描述
因此更规范的方法是用defineProperty方法来修复constructor的指向,并控制访问权限。

function Dog() {     this.name = 'puppy'}Dog.prototype.bark = () => {     console.log('woof!woof!')}function BigDog() {   }BigDog.prototype = new Dog()// 修复constructor的指向Object.defineProperty(BigDog.prototype, "constructor", {           value: BigDog,        enumerable: false,      })const bigDog = new BigDog()console.log(bigDog.constructor === BigDog)

如果用上面两个问题去测试,会发现ES6中的class实际是上面这种写法的语法糖实现。

class Cat {       constructor(props) {         this.name = 'puppy'    }  }class BigCat extends Cat {       constructor(props) {         super(props)    }}const bigCat = new BigCat()console.log(bigCat.constructor === BigCat) //truefor(let i in bigCat){   console.log(i)} // 不会出现constructor属性
上一篇:浅层次理解Promise思想及其简单应用
下一篇:JS中的几种对象创建模式

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2025年04月21日 03时07分38秒