本文已参与「新人创作礼」活动,一起开启掘金创作之路
对继承一直迷迷茫茫,抽个下午出来总结一下
继承的几种方式
graph LR
A[继承]-->B-->D-->G
A-->C-->D
A-->E-->F-->G
B[原型链式继承]
C[借用构造函数]
D[组合式继承]
E[原型式继承]
F[寄生式继承]
G[组合寄生式继承]
原型链继承
- 要继承的函数
- 给父亲的原型一个方法
- 一个子函数
- 子函数的prototype = new父函数(获得父函数的实例)
- (如果需要可以给子函数的原型添加其他方法)
- (new 子函数,获得实例)
缺点
多个实例对引用类型的操作会被篡改。
实现
function father(){
this.name = "father"
}
father.prototype.say = function(){
return this.name
}
function son(){
this.childName = "Child"
}
son.prototype = new father()
let son1 = new son()
console.log(son1.say())
借用构造函数继承
- 要继承的父函数
- 子函数:调用父函数,使用call改变this指向
- (new 子函数,获得实例)
缺点
只能继承父类的实例属性和方法,不能继承原型属性和方法,无法实现复用,每个子类都有父类实力函数的副本,影响性能
实现
function father(){
this.name = "father"
}
function son(){
father.call(this)
}
let son1 = new son()
组合继承
用原型链方法实现对原型属性和方法的继承,用借用构造函数技术来实现实例属性的集成。
- 需要继承的父函数
- 向父函数的原型上添加个方法
- 子函数,在子函数内部调用父函数,使用call改变this指向,继承属性,子函数可以添加新属性
- 子函数的原型=父函数的实例
- 子函数原型里的构造函数=子函数(在上一步 子函数原型的构造函数指向了父函数,指回来,因为在默认情况下,一个函数对象的原型的contructor属性指向这个函数对象, )
- (如果喜欢可以给子函数的原型增加一些方法)
- (new子函数 获得实例)
缺点
在使用子类创建实例对象时,其原型中会存在两份相同的属性/方法
实现
function father(name){
this.name = name
}
father.prototype.say=function(){
return this.name
}
function son(name,age){
father.call(this,name)
this.age=age
}
son.prototype = new father()
son.prototype.constuctor = son
原型式继承
利用空对象作为中介,将某个对象直接赋值给空对象的原型
- 一个需要继承的对象
- let 新对象 = Object.create(旧对象)
实现
let person = {
name:"haha",
family:['papa','mama']
}
let me = Object.create(person)
手写object.create()
function mycreate(){
funciton f(){}
f.prototype = obj
return new f()
}
缺点
无法传递参数;原型链继承多个实例的引用类型属性指向相同,存在篡改的可能
寄生式继承
在原型式继承的基础上,增强对象,为构造函数新增属性和方法
-
一个需要继承的对象
-
手写一个实现寄生式继承的函数f
- 传入obj,let 新对象 = object.create(obj)
- 给新对象增加方法(这里大大增强了)
- 返回新对象
-
let 新对象 = f(旧对象)
缺点
同原型式继承
实现
let person = {
name:"haha",
family:['papa','mama']
}
function giveMeInheritance(obj){
let newObj = Object.create(obj)
newObj.function1 = function(){
return "function1"
}
return newObj
}
let me = giveMeInheritance(person)
寄生式组合继承
-
一个需要继承的父类(函数),为父类原型添加方法
-
一个子类函数,在子类里调用父函数,call改变指向
-
写寄生继承的函数f
- 传入子类和父类
- let 临时对象 = 创建父类原型的一个副本
- 使临时对象的构造函数=子类
- 子类的原型对象= 临时对象
-
调用寄生继承的函数f
-
(如果喜欢可以给子函数的原型增加一些方法)
-
(new子函数 获得实例)
实现
function father(name){
this.name = name
}
father.prototype.say = function(){
return this.name
}
function son(name,age){
father.call(this,name)
this.age=age
}
function inherit(son,father){
let prototype1 = Object.create(father.prototype)
prototype1.constructor = son
son.prototype = prototype1
}
inherit(son,father)