作者:DBCdouble

https://juejin.im/post/6869689622676471816

一、前言

相信很多人在遇到面试中都遇到过被问到过JavaScript继承模式的问题,都能手写出几种继承模式的代码例子,但为什么面试官却对你的回答不是很满意或者压根就没听懂,个人觉得应该是缺少自己的一个答题的思路。

二、答题技巧

  • 第一,按照几种继承模式的从最次的继承模式到最佳的继承模式的顺序去讲

  • 第二,讲出当前这种继承模式的利弊相对前一种继承模式解决了什么问题,最关键的代码部分在哪里

以下着重讲一下几种常见的几种继承模式

二、原型链继承

代码示例

function Parent (sex) {this.sex = sex
}Parent.prototype.setSex = function () {}function Son (name) {this.name = name
}Son.prototype = new Parent()
var s1 = new Son('DBCDouble')
console.log(s1)

结果打印

关键:子类的原型指向父类的实例,从而继承父类私有属性原型属性

优点:

  • 父类新增原型属性和方法,子类实例都能访问到

  • 简单、易用

缺点:

  • 无法实现多继承(一个子类继承成多个父类)

  • 创建子类实例的时候,无法向父类构造函数传参

  • 有子类实例共享父类引用属性的问题(因为子类的原型指向的是父类的一个实例,假如父类的私有属性有一个是数组(引用类型),那么任一子类都可以操作这个数组,从而导致其他子类使用的这个数组也会发生变化)

四、借用父类构造函数继承

代码示例

function Parent (sex) {this.sex = sex
}Parent.prototype.setSex = function () {}function Son (name, age, sex) {Parent.call(this, sex)this.name = namethis.age = age
}
var s1 = new Son('DBCdouble', 25, '男')
console.log(s1)

结果打印

关键:在子类构造函数中使用call或者apply调用父类构造函数实现父类私有属性继承(函数复用)

优点:

  • 创建子类实例时,可以向父类传递参数

  • 可以实现多继承(在子类构造函数调用多个父类构造函数)

  • 解决了原型链继承中子类实例共享父类引用属性的问题(即使父类构造函数中有引用类型,在创建子类实例时,都会重新调用父类构造函数重新创建一份这个引用类型数据,重新申请引用类型的空间)

缺点:

  • 每次创建子类实例时,都要调用一次父类构造函数,影响性能

  • 只继承父类的实例属性(私有属性),没有继承父类的原型属性

五、组合式继承(原型链继承 + 借用构造函数继承)

代码示例

function Parent (sex) {this.sex = sex
}Parent.prototype.setSex = function () {}function Son (name, age, sex) {Parent.call(this, sex)this.name = namethis.age = age
}
Son.prototype = Object.create(Parent.prototype)
Son.prototype.constructor = Son
var s1 = new Son('DBCdouble', 25, '男')
console.log(s1)

打印结果

关键:通过调用父类构造函数,继承父类的属性并保留传参的优点,并通过Object.create(Parent.prototype)来创建继承了父类原型属性的对象,并把这个对象赋给子类的原型,这样的话,既能保证父类构造函数不用执行两次,又能让子类能继承到父类的原型方法

优点:

  • 创建子类实例时,可以向父类传递参数

  • 可以实现多继承(在子类构造函数调用多个父类构造函数)

  • 解决了原型链继承中子类实例共享父类引用属性的问题(即使父类构造函数中有引用类型,在创建子类实例时,都会重新调用父类构造函数重新创建一份这个引用类型数据,重新申请引用类型的空间

  • 父类构造函数只用执行一次

六、ES6的class继承

ES6中引入了class关键字,class可以通过extends关键字实现继承,还可以通过static关键字定义类的静态方法,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。

注意:ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法加到this上面(所以必须先调用super方法)然后再用子类的构造函数修改this

代码示例

class A {constructor (sex) {this.sex = sex}showSex () {console.log('这里是父类的方法')}
}class B extends A {constructor (name, age, sex) {super(sex);this.name = name;this.age = age;}showSex () {console.log('这里是子类的方法')}
}const b = new B('DBCDOUBLE', 25, '男')
console.log(b);

打印结果

关键:使用extends关键字继承父类的原型属性,调用super来继承父类的实例属性,且保留向父类构造函数传参的优点

优点:简单易用,不用自己来修改原型链来完成继承

我们通过将代码从ES6编译到ES5来看看到底,class继承的代码最终会被编译成什么样,如下:

从上图分析得到:

  • 上述代码示例中的super指的就是父类构造函数

  • 子类继承父类的实例属性最终还是通过call或者apply来实现继承的

  • 通过extends方法的调用来修改子类和父类的原型链关系

再看经过编译后的extends方法,如下

1、注意Object.setPrototypeOf()方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null
2、(.prototype = b.prototype, new ())表达式的执行执行顺序是先执行前者,再返回后者

从上图可知,extends做了以下几件事:

  • 定义了一个function __() {}函数,并把该函数的constructor指向了子类

  • 紧接着,把function __() {} 函数的原型指向了父类的原型

  • 最后再把function () {} 函数的实例赋给了子类函数,就这样子类的实例就能沿着proto.proto获取到父类的原型属性了,这种继承模式俗称圣杯模式

特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:

长按订阅更多精彩▼如有收获,点个在看,诚挚感谢

为什么你老是讲不清楚js的继承模式相关推荐

  1. oncreate为什么一定要调用父类的oncreat_为什么你老是讲不清楚JS的继承模式

    点击上方 "前端技术精选" 关注,星标或者置顶 17点30分准时推送,第一时间送达 作者:DBCdouble | 编辑:前端妹 来自:juejin.im/post/68696896 ...

  2. 你真的理解JS的继承了吗?

    噫吁嚱,js之难,难于上青天 学习js的这几年,在原型链和继承上花了不知道多少时间,每当自以为已经吃透它的时候,总是不经意的会出现各种难以理解的幺蛾子.也许就像kyle大佬说的那样,js的继承真的是' ...

  3. 5讲项目实战js第二区域轮播器及选项卡

    #5讲项目实战js第二区域轮播器及选项卡  <!--整站建设步骤如下:   1.构建一个宽度100% 高度149px 这样一个长方形,为了保证浏览器的兼容,我们加了*{margin:0px;pa ...

  4. #6讲项目实战js第三区域响应式菜单

    #6讲项目实战js第三区域响应式菜单   <!--整站建设步骤如下:   1.构建一个宽度100% 高度149px 这样一个长方形,为了保证浏览器的兼容,我们加了*{margin:0px;pad ...

  5. 7讲项目实战js第三区域响应式菜单续

    #7讲项目实战js第三区域响应式菜单<续>   <!--整站建设步骤如下:   1.构建一个宽度100% 高度149px 这样一个长方形,为了保证浏览器的兼容,我们加了*{margi ...

  6. Js Call方法详解(js 的继承)

    call 方法 请参阅 应用于:Function 对象 要求 版本 5.5 调用一个对象的一个方法,以另一个对象替换当前对象. call([thisObj[,arg1[, arg2[, [,.argN ...

  7. js中继承的几种用法总结(apply,call,prototype)

    本篇文章主要介绍了js中继承的几种用法总结(apply,call,prototype) 需要的朋友可以过来参考下,希望对大家有所帮助 一,js中对象继承 js中有三种继承方式 1.js原型(proto ...

  8. (转)js实现继承的5种方式

    js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承有以下通用的几种方式 1.使用对象冒充实现继承(该种实 ...

  9. js 原型prototype继承模式

    js中利用原型prototype的方式实现继承是最常见的继承模式,如果让a的实例继承b,原型prototype的继承方式如下: function A(){} function B(){} A.prot ...

最新文章

  1. yii2 / 在这里有个叫BaseDataProvider的老爹
  2. [学习笔记]标记永久化
  3. 琥珀项目:Java的未来揭晓
  4. hibernate get方法有执行sql但是后台拿不到_「6」进大厂必须掌握的面试题-Hibernate...
  5. Linux学习总结(27)——CentOS7及以上系统的systemctl命令使用介绍
  6. Python_Day10_进程、线程、协程
  7. Tomcat启动过程(一):从BootStrap到EndPonit
  8. 华为笔记本支持鸿蒙,华为 EMUI11 多屏协同说明新增支持鸿蒙 2.0 手机连接
  9. [转]常见hash算法的原理
  10. 【GIF图片】用PS生成背景透明的GIF图片出现帧叠加的现象
  11. obj文件(3): 如何用matlab 打开obj文件
  12. 【白话科普】从“熊猫烧香”聊聊计算机病毒
  13. 1056: 兔子繁殖问题
  14. 物联网安全研究之二:IoT系统攻击面定义分析
  15. “东数西算”取得新进展,发改委等四部门发文构建国家算力网络体系 | 产业区块链发展周报...
  16. API卡_[api]必应词典查询api,naive implementation
  17. 服务器监控-prometheus使用(4):收集器搭建篇
  18. 苹果应用商店审核_苹果应用商店审核流程更新:给开发者申诉的机会
  19. yjk的波库在哪里_专题文档
  20. 计算机技术在现代地球科学中的重要性,论地质勘察在现代工程勘察中的重要性...

热门文章

  1. xgboost 正则项_XGBoost入门系列第一讲
  2. %3c- r语言运算符,R语言基础教程之运算符
  3. df满足条件的值修改_文科生学 Python 系列 16:泰坦尼克数据 2(缺失值处理)
  4. tensorflow中的梯度弥散与梯度爆炸
  5. HDU2222(AC自动机模版题)
  6. win 10升级后不能访问服务器文件夹,Win10打开某些文件夹出现“无法访问”的解决方法...
  7. nginx 负载 sessionid 不一致_你不知道的Nginx负载均衡算法,快进来迅速掌握
  8. 2019 ICPC全国邀请赛(西安)I. Cracking Password(序列检验,BSGS,细节题)
  9. Luogu P4105 [HEOI2014]南园满地堆轻絮
  10. android 滑动顶部固定,android view滑动到顶部悬停