谈谈JS继承

1、原型链继承

如果想深入了解更多原型的内容,可以参考之前的文章

function Parent(value) {
	this.parentVal = 'parent'
}
Parent.prototype.getParentValue = function() {
	return this.parentVal
}

function Child() {
	this.childVal = 'child'
}
Child.prototype = new Parent()

var child = new Child()
child.getParentValue() // 'parent'

这里 Child 继承了 Parent,实现的本质是重写原型对象 Child.prototype,代之以一个新类型的实例 new Parent()。
so,原来存在于 Parent 的实例中的所有属性和方法,现在也存在于 Child.prototype 中了
关系图如下:
在这里插入图片描述
原型链的问题
1、包含引用类型值的原型属性会被所有实例共享
在通过原型来实现继承时,原型实际上会变成另一个类型的实例。于是,原先的实例属性也就顺理成章地变成了现在的原型属性了,这样就可能引起问题,见下🌰:

function Parent(value) {
	this.foods = ['apple', 'banana']
}

function Child() {
	this.childVal = 'child'
}
Child.prototype = new Parent()

var child1 = new Child()
var child2 = new Child()
child1.foods.push('pear')
child1.foods // ["apple", "banana", "pear"]
child2.foods // ["apple", "banana", "pear"]

在实现原型链的过程中,这里的 foods 属性从Parent的实例属性转化为Child的原型属性了,所以Child的所有实例都会共享foods,一改全改
2、不能传递参数
没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数

2、借用构造函数实现继承

在子类型构造函数中通过 call() “借调”父类型的构造函数,可以解决原型中包含引用类型值所带来问题,见下🌰:

function Parent(value) {
	this.foods = ['apple', 'banana']
}

function Child() {
	//继承了 Parent
	Parent.call(this)
}
Child.prototype = new Parent()

var child1 = new Child()
var child2 = new Child()
child1.foods.push('pear')
child1.foods // ["apple", "banana", "pear"]
child2.foods // ["apple", "banana"]

还支持传递参数,见下🌰:

function Parent(name) {
	this.name = name
}

function Child() {
	//继承了 Parent
	Parent.call(this, 'sally')
	this.age = 23
}
Child.prototype = new Parent()

var child = new Child()
child.name // 'sally'
child.age // 23

构造函数继承的问题
方法都在构造函数中定义,无法实现函数复用。而且,在父类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式

3、组合继承

将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式

function Parent(value) {
	this.val = value
}
Parent.prototype.getValue = function() {
	console.log(this.val)
}
function Child(value) {
	Parent.call(this, value)
}
Child.prototype = new Parent()

const child = new Child(1)

child.getValue() // 1

以上继承的方式核心是在子类的构造函数中通过 Parent.call(this) 继承父类的属性,然后改变子类的原型为 new Parent() 来继承父类的函数

优点: 构造函数可以传参,不会与父类引用属性共享,可以复用父类的函数
缺点: 在继承父类函数的时候调用了父类构造函数,导致子类的原型上多了不需要的父类属性,存在内存上的浪费。

4、寄生组合继承

这种继承方式对组合继承进行了优化

function Parent(value) {
	this.val = value
}
Parent.prototype.getValue = function() {
	console.log(this.val)
}

function Child(value) {
	Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
	constructor: {
		value: Child,
		enumerable: false,
		writable: true,
		configurable: true
	}
})

const child = new Child(1)
child.getValue() // 1

以上继承实现的核心就是将父类的原型赋值给了子类,并且将构造函数设置为子类,这样既解决了无用的父类属性问题,还能正确的找到子类的构造函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值