js继承的几种方式,圣杯模式

继承,在面向对象的编程中用的还是非常多的,虽然面向对象因为其复杂的构建对象的初始化,在大多数的程序中并没用用到,但是我们使用过后才发现,这使得今后项目的扩展和维护更加容易。话不多说,进入正题。

1. 传统形式(原型链继承)

//父类
Father.prototype.name = "Li"
function Father() {
	this.age = 18
}
//子类
Son.prototype = new Father()
function Son() {}

var son = new Son()

这种方法确实可以继承到name属性。son.name也确实是"Li",我们输出son.age也可以得到18。
在这里插入图片描述
但是Son的构造函数中并没有age属性,该属性是Son.prototype中的。

缺点:并没有把父级的age属性继承到Son的构造函数中,而是放到了Son.prototype中,这并不是我们想要的

2. 借用构造函数继承

//父类
Father.prototype.name = "Li"
function Father() {
	this.age = 18
}
//子类
function Son() {
	Father.call(this)
}

var son = new Son()

这种方法可以实现Son构造函数中有age属性
在这里插入图片描述
我们从图片中可以看出,虽然Son中是有了age属性,但是Son.prototype还是自己的原型,并没有继承自父类

缺点:1.不能继承借用构造函数的原型。2.每次用Son构造对象时,都会执行两个构造函数,造成资源浪费

3. 共享原型

//父类
Father.prototype.name = "Li"
function Father() {
	this.age = 18
}
//子类
function Son() {
	Father.call(this)
}

Son.prototype = Father.prototype
var son = new Son()

这种写法看似没有问题,age被放到了Son构造函数中,父类原型上的name属性也继承来了
在这里插入图片描述
但是我们忽略了一点,不管是Son的prototype还是Father的prototype,他们都是一个对象,对象之间的赋值是地址的传递。所以当我们改变Father原型上的属性时,Son原型也会被修改。因为Son.prototype = Father.prototype这句话使他们指向了一个内存空间

缺点:原型之间改变相互影响

4. 圣杯模式

总结了上述方式缺点之后,慢慢的就演变成了现在在用的完美的继承方式,至于"圣杯模式"这个名字的由来,大家感兴趣的话还是自己查阅资料,"圣杯"简单来说就是"永恒"的意思,这里不做过多的讨论。

//父类
Father.prototype.name = "Li"
function Father() {
	this.age = 18
}
//子类
function Son() {
	Father.call(this)
}
//中间构造函数
function Temp() {}

Temp.prototype = Father.prototype
Son.prototype = new Temp()
var son = new Son()

我们借用一个空的构造函数与Father共享原型,然后让Son的原型指向Temp的实例就可以完美解决以上问题。

解析:Temp.prototype = Father.prototype,使Temp.prototype和Father.prototype指向同一个内存空间,并不会影响Son.prototype。此时Son.prototype = new Temp()相当于Son.prototype__proto__ = Temp.prototype,也就是Son.prototype__proto__ = Father.prototype。从而实现了继承。

优化:

  • 我们可以将它封装为一个方法,因为每次继承都会创建一个新的Temp中间函数,造成了资源浪费。优化代码如下
var inherit = (function () {
	var Temp = function() {}
	return function (Target, Origin) { //target继承自origin
		Temp.prototype = Origin.prototype
		Target.prototype = new Temp()
		Target.prototype.constructor = Target //为了让Target原型的constructor指回Target
		Target.prototype.uber = Origin.prototype //找到自己的超类
	}
})()
  • 由于es6有了Object.create()方法,可以改变函数的隐式原型(_proto_),也可以不用中间函数
function inherit(Target, Origin) {
	Target.prototype = Object.create(Origin.prototype)
	Target.prototype.constructor = Target
	Target.prototype.uber = Origin.prototype
}

到此,就是继承的圣杯模式的最终写法了!

5.es6继承方式

class Father {
	constructor() {
		this.age = 18
	}
}
class Son extends Father {
	constructor() {
		super()
	}
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值