JavaScript面向对象(2)—继承的实现
JavaScript面向对象—继承的实现
前言
面向对象的三大特性:封装、继承和多态。上一篇我们简单的了解了封装的过程,也就是把对象的属性和方法封装到一个函数中,这一篇讲一下JavaScript中继承的实现,继承是面向对象中非常重要的特性,它可以帮助我们提高代码的复用性。继承主要的思想就是将重复的代码逻辑抽取到分类中,子类只需要通过继承分类,就可以使用分类中的方法,但是在实现JavaScript继承之前,需要先了解一个重要的知识点“原型链”。
1.JavaScript中的原型链
在上一篇JavaScript面向对象—对象的创建和操作中已经简单的了解过了JavaScript中对象的原型和函数的原型,当我们从一个对象上获取属性时,如果在当前对象自身没有找到该属性的话,就会去它原型上面获取,如果原型中也没有找到就会去它原型的原型上找,沿着这么一条线进行查找,那么这条线就是我们所说的原型链了。
示例代码:
对应的内存中的查找过程:
当通过原型链查找某个属性时,一直找不到的话会一直查找下去么?肯定是不会的,JavaScript的原型链也是有尽头的,这个尽头就是Object的原型。
2.Object的原型
事实上,不管是对象还是函数,它们原型链的尽头都是Object的原型,也称之为顶层原型,我们可以打印看看这个顶层原型长什么样。
(1)打印Object的原型
- 在node环境中:
- 在浏览器中:
(2)Object原型的特殊之处
-
如果我们再次打印
Object.prototype
的原型,这个原型属性已经指向了null; -
并且在
Object.prototype
上有很多默认的属性和方法,像toString、hasOwnProperty
等;
(3)上一篇中讲到当使用new操作符调用构造函数时,其对象的[[prototype]]
会指向该构造函数的原型prototype
,其实Object
也是一个构造函数,因为我们可以使用new操作符来调用它,创建一个空对象。
(4)总结
- 从Object的原型可以得出一个结论“原型链最顶层的原型对象就是Object的原型对象”,这也就是为什么所有的对象都可以调用
toString
方法了; - 从继承的角度来讲就是“Object是所有类的父类”;
3.JavaScript继承的实现方案
3.1.方案一:通过原型链实现继承
如果需要实现继承,那么就可以利用原型链来实现了。
- 定义一个父类
Person
和子类Student
; - 父类中存放公共的属性和方法供子类使用;
- 核心:将父类的实例化对象赋值给子类的原型;
内存表现:
缺点:
- 从内存表现图中就可以看出,当打印stu对象时,name和age属性是看不到的,因为不会打印原型上的东西;
- 当父类中的属性为引用类型时,子类的多个实例对象会共用这个引用类型,如果进行修改,会相互影响;
- 在使用该方案实现继承时,属性都是写死的,不支持动态传入参数来定制化属性值;
3.2.方案二:借用构造函数实现继承
针对方案一的缺点,可以借用构造函数来进行优化。
- 在子类中通过call调用父类,这样在实例化子类时,每个实例就可以创建自己单独属性了;
内存表现:
缺点:
- 在实现继承的过程中,Person构造函数被调用了两次,一次在
new Person()
,一次在Person.call()
; - 在Person的实例化对象上,也就是stu1和stu2的原型上,多出来了没有使用的属性name和age;
3.3.方案三:寄生组合式继承
通过上面两种方案,我们想实现继承的目的是重复利用另外一个对象的属性和方法,如果想解决方案二中的缺点,那么就要减少Person的调用次数,避免去执行
new Person()
,而解决的办法就是可以新增一个对象,让该对象的原型指向Person的原型即可。
(1)对象的原型式继承
将对象的原型指向构造函数的原型的过程就叫做对象的原型式继承,主要可以通过以下三种方式实现:
-
封装一个函数,将传入的对象赋值给构造函数的原型,最后将构造函数的实例化对象返回;
-
改变上面方法中的函数体实现,使用
Object.setPrototypeOf()
方法来实现,该方法设置一个指定的对象的原型到另一个对象或null; -
直接使用
Object.create()
方法,该方法可以创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
;
(2)寄生组合式继承的实现
寄生式继承就是将对象的原型式继承和工厂模式进行结合,即封装一个函数来实现继承的过程。而这样结合起来实现的继承,又可以称之为寄生组合式继承。下面就看看具体的实现过程吧。
- 创建一个原型指向
Person
父类的对象,将其赋值给Student
子类的原型; - 在上面的实现方案中,
Student
子类的实例对象的类型都是Person
,可以通过重新定义constructor
来优化;
内存表现:
总结:
-
多个地方用到了继承,可以将上面的核心代码赋值在一个函数里面,如果不想用
Object.create()
,也可以使用上面封装的createObj
函数; -
寄生组合式实现继承的原理其实就是创建一个空对象用于存放子类原型上的方法,并且这个对象的原型指向父类的原型,在ES6中推出的class的实现原理就在这;
__EOF__

本文链接:https://www.cnblogs.com/MomentYY/p/15999285.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix