首先我们要知道继承是要做什么的, 是为了节省内存消耗, 避免重复调用问题
warning
本篇文章建立在已经有所了解JavaScript继承的情况下去进行进一步梳理(原创
)
简述
并且既然叫做JavaScript继承, 那么这几个问题都是围绕怎样实现继承
用抄袭试卷的方式来讲解,
原型相当于答案的最开始来源处
constructor相当于最后的签名
你总不能把别人的名字一起抄上去吧, 这代表签名, 这份试卷是你自己的
如果我要实时了解你的试卷, 那我就要指定原型是你, 相当于构建一个单向偷窥隧道
当然如果也有其他人偷窥你的试卷, 那么我和那个人就是共享原型, 原型是你的试卷
1. 构造函数继承
(继承构造函数
), 也叫类抄写, 比如我们在考试, 你写了一个构造函数, 我要继承你的构造函数, 就在我的构造函数里面用call或者cpply抄写一份你的东西, 我给你题目你给我答案
, 当然我抄完后还可以在自己的构造函数的选做题
里面放一些自己的东西
因为我只是抄了你的东西, 但是我们并不是公用一份, 所以, 我们两个构造函数是独立的
缺点是, 因为不是共享, 是一次性拷贝
, 也就是如果你后面修改了你的答案我是不知道的, 除非我再抄你一遍
2. 原型链继承
也叫类继承(也是继承构造函数
), 最简单的继承, 比如老大是原型, 你是二当家, 其他人都是小弟都叫实例继承了二当家, 当然默认也是继承了老大
, 我们这个帮派一旦老大或者二当家有政策发布, 下面的小弟都要修改
这就是原型链继承,
缺点是, 上级改动, 下级都要跟着修改
3. 组合继承
(继承构造函数
), 什么意思, 我们在构造函数基础的基础上再进行讲述
我还是要抄你试卷, 首先我还是要全抄!!!
, 因为你是学霸
但是我不想只抄一遍, 你有些大题改了我也要知道, 所以你就把你的试卷分成两部分, 一部分是给我给你题目你给我对于的答案, 这部分放在构造函数内
, 你可能要修改的部分改了要告诉我, 你就把答案放在你的原型里面
你改了我也改
当然我也可以有自己的想法, 可以加一些自己的答案
缺点: 调用了两次父类构造函数, 耗费内存, 第一次是让你帮我做题, new一个你的构造函数返回给我, 目的是为了成为你的实例好去引用你的原型
使用 new 操作符调用了一次 构造函数
有方法避免多次调用直接去掉 new 操作符
写成 Child.prototype = Parent.prototype
但是这样并不好,虽然避免出现重复调用但导致修改子类 constructor 的时候父类也被修改了, 也就是
如果我再试卷上签了自己的名字
那么意味着你的原型的构造者不在是你的构造函数, 而是我的了
这是组合式继承的唯一缺点
4. 原型式继承(继承对象
) ———————注意是对象
用es5的object.create(对象)返回一个实例给我抄
原理是浅拷贝
我直接抄袭你的对象, 我不想改, 没有想法
抄袭对象的话不用签名的, 也就是不用constructor
5. 寄生式继承(继承对象
)———————注意是对象
原型式继承的基础上为子类增加属性和方法, 就是继承了对方也添加了自己的方法
6. 寄生组合式继承
解决了之前组合继承的两次调用父类构造函数问题
那么第一次调用父类构造函数是不可避免的, 就是parent.call(this)这个是不可省略的
要精简的是组合式继承的第二次通过调用new Parent()
想办法来解决这次的调用
之前说过不用new,改用parent.prototype来公用同一个原型是不合理的
因为如果我的原型的constructor指向了我自己的构造函就会导致原型的constructor也会改成我的构造函数, 就不合理了, 因为原型的构造函数还是要指向我的父类的
那么就可以用到原型式继承
的解决方案来解决, 即在原型中间新建一个空的构造函数作为中介, 然后如果我执行child.prototype.constructor=child就不会影响parent.constructor指向我会变成空构造函数的构造者变成了我
从而解决了问题
7. es6的calss继承(推荐使用
)
挺优秀的方式, 推荐使用, 语法很清晰
class Parent {
constructor(name, friends) { // 该属性在构造函数上,不共享
this.name = name
this.friends = friends
}
log() { // 该方法在原型上,共享
return this
}
}
Parent.prototype.share = [1, 2, 3] // 原型上的属性,共享
class Child extends Parent {
constructor(name, friends, gender) {
super(name, friends) // 继承父类构造函数
this.gender = gender
}
}