【继承系列】JS中的原型链继承

1. 原型链继承

将子类的原型对象指向父类的实例

1.1 题目一
function Parent () {
  this.name = 'Parent'
  this.sex = 'boy'
}
Parent.prototype.getName = function () {
  console.log(this.name)
}
function Child () {
  this.name = 'child'
}

// 将Child的原型对象指向Parent的实例对象
Child.prototype = new Parent()

const child1 = new Child()
child1.getName()
console.log(child1)

答案

'child'
Child {name: "child"}

理解:

  • child1是Child的实例对象,有属性name
  • 子类构造函数Child它的原型被指向了父类构造函数Parent创建出来的"无名实例"
  • 这样的话,我child1就可以使用你这个"无名实例"里的所有属性和方法,因此child1.getName()有效。console.log(this.name)这里因为child1中有属性name,就不再沿原型链寻找name,可以尝试把Child中name去掉,结果就是Parent
  • 另外由于sex、getName都是Child原型对象上的属性,所以并不会表现在child1上。

这就是原型链继承,我们看张图,我是喜欢用三角来画原型三角恋的

在这里插入图片描述

所以现在你知道了吧,这种方式就叫做原型链继承。

将子类的原型对象指向父类的实例。

1.2 题目二

注意原型链继承不是 A原型 = B原型

function Parent () {
  this.name = 'Parent'
  this.sex = 'boy'
}
Parent.prototype.getSex = function () {
  console.log(this.sex)
}
function Child () {
  this.name = 'child'
}
Child.prototype = Parent.prototype

const child1 = new Child()
child1.getSex()
console.log(child1)

这道题是错误的,只想说明上面这种方式是错误的

1.3 题目三

理解原型链继承的优点和缺点

function Parent (name) {
  this.name = name
  this.sex = 'boy'
  this.colors = ['white', 'black']
}
function Child () {
  this.feature = ['cute']
}

const parent = new Parent('parent')

Child.prototype = parent

const child1 = new Child('child1')

child1.sex = 'girl'
// child1.colors = ['test']
child1.colors.push('yellow')
child1.feature.push('sunshine')

const child2 = new Child('child2')
child2.feature.push('rain')

console.log(child1.name)
console.log(child1.colors)
console.log(child1.feature)

console.log(child2.colors)
console.log(child2.feature)
console.log(parent)

答案:

parent
VM278:24 (3) ["white", "black", "yellow"]
VM278:25 (2) ["cute", "sunshine"]
VM278:27 (3) ["white", "black", "yellow"]
VM278:28 (2) ["cute", "rain"]
VM278:29 Parent {name: "parent", sex: "boy", colors: Array(3)}
  • 在child1实例中添加了一个新属性sex

  • child1是没有colors属性的,需要去原型链上去寻找,找到colors并pushyellow,此时修改的是parent上的属性,会影响到后续所有的实例对象

  • (这里可能会有疑问,为什么child1.colors不是在child1上新增,而sex就是,说下我的理解)

    • 设置colors时候,是先取到colors,发现parent上有colors,再进行push方法,如果你直接child1.colors = ['test'],那么child1中就会有你创建的这个colors2,那么push的yellow也就在colors2中
    • 设置sex时候,不用先取到sex,可直接赋值,于是就在child1实例中直接创建sex属性
  • child2.colors由于用的也是原型对象parent上的colors,又由于之前被child1给改变了,所以打印出来的会是['white', 'black', 'yellow']

  • feature它是属于实例自身的属性,它添加还是减少都不会影响到其他实例。

  • child1.name是原型对象parent上的name,也就是’parent’,虽然我们在new Child的时候传递了’child1’,但它显然是无效的,因为接收name属性的是构造函数Parent,而不是Child。

2.总结

现在我们就可以得出原型链继承它的优点和缺点了

优点:

  • 继承了父类的模板,又继承了父类的原型对象
    缺点:

  • 来自父类构造函数的所有属性都被共享了,这样如果不小心修改了父类构造函数中的引用类型属性,那么所有子类创建的实例对象都会受到影响(这点从修改child1.colors可以看出来)

  • 如果要给子类的原型上新增属性和方法,就必须放在Child.prototype = new Parent()这样的语句后面,如果放在前面当然找不到原型呀,因为这句话连接了父类与子类(具体看图)

  • 创建子类时,无法向父类构造函数传参数(这点从child1.name可以看出来)

参考文章:

48道原型题目

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值