博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
小议JS原型链、继承
阅读量:6218 次
发布时间:2019-06-21

本文共 2546 字,大约阅读时间需要 8 分钟。

继承是前端面试必问,说到继承,就必须谈一谈原型链。

原型链

我面试的时候都会这么回答原型链:js万物皆对象,用var a={} 或 var a = new Object()或者用构造函数的形式:var a = new A()创建一个对象时,该对象不仅可以访问它自身的属性,还会根据__proto__属性找到它原型链上的属性,直到找到Object上面的null。如有不贴切,望评论不足之处哈。

更详细的参考mdn:

对于下面的例子:

var A = function(){    this.name="xiaoming";}A.prototype.age=9;var a = new A();console.log(a.age); //9复制代码

我参考以前学习java时对实例和Class的图画了一个原型链的图,不太好,但是画图不易,小女子求您一个赞哈。

言归正传,图中长方形代表实例对象a,圆形代表原型,三角形代表构造函数。由图可知:

a.__proto__ === A.prototype; //trueA.prototype.constructor===A; //trueA.prototype.__proto__===Object.prototype; //trueObject.prototype.__proto__===null; //true复制代码

上方示例可以在看完我的解释之后再回顾一遍。实例和原型之间是通过__proto__属性连接,且是单向的,从实例指向原型原型和构造函数之间连接是双向的,通过constructor和prototype连接,具体见图;原型链上的属性是所有实例共享的,看下面的例子:

var A = function(){    this.name="xiaoming";}var a = new A();A.prototype.age=9;var b = new A();console.log(a.age); //9console.log(b.age); //9复制代码

a、b都可以访问A原型链上的属性age。

Function和Object比较特殊,他们既是对象又是函数,两者内部同时含有proto和prototype属性,可看下面代码:

Object.__proto__ === Function.prototype //trueObject.__proto__ === Function.__proto__//trueObject.prototype === Function.prototype.__proto__ // trueFunction instanceof Object //trueObject instanceof Function //true复制代码

至此,原型链的知识差不多可以理解了,后面介绍继承的几种方式。

原型链继承

既然可以访问原型链的所有属性,那么就可以用原型链的原理实现继承。原型链继承用new的方式(实现A继承B):

A.prototype=new B();关于new可以看下我另一篇文章。

代码:

function B(){    this.nameB='B';}B.prototype.nameProto="PROTO";function A(){    this.nameA="A";}A.prototype=new B(); //原型链继承:A继承Bvar a=new A();console.log(a);复制代码

打印结果:

上段代码A继承B,
通过A构造函数new的示例a不仅可以继承B(可访问nameB),而且可以继承B原型上的属性(nameProto),且是所有实例共享的。

好处:可以继承原型链的属性

缺点:无法实现多继承,A继承了B,就无法再继承C

构造继承

构造继承就是利用构造函数继承,即改变this指向的方式(call/apply/bind)执行一次构造函数B,具体可我另一篇文章。废话不多说,上例子:

function B(){    this.nameB='B';}B.prototype.nameProto="PROTO";function A(){    B.call(this); //A继承B,只举了call的例子,apply、bind类似    this.nameA="A";}var a=new A();console.log(a);复制代码

打印结果:

根据a的打印结果,我们看到nameB和nameA是同一层级,虽然实现了A继承B,但是通过a的结构看不出来,而且
无法继承B原型链上的属性nameProto,不过它的好处是可以
多继承,可以通过
C.call(this)继承C。

好处:可以多继承

缺点:无法继承原型链上的属性

组合继承

组合继承就是为了解决原型链继承无法多继承、构造继承无法继承原型链上的属性的问题而诞生的,将两种方式结合。

function B(){    this.nameB='B';}B.prototype.nameProto="PROTO";function A(){    B.call(this); //构造继承    this.nameA="A";}A.prototype=new B(); //原型链继承:A继承Bvar a=new A();console.log(a);复制代码

打印结果:

观察a的打印结果,似乎真的解决了上述两个问题,它也引入了一个新的问题:
nameB属性有两个,这样造成了资源浪费(存储占用内存)。

原型式继承

先看下面的示例:

function objectCreate(obj){  function F(){};  F.prototype = obj;  return new F();}var a=objectCreate(A.prototype);复制代码

上个例子中,

  1. 使用__proto__A.prototype.__proto__=B.prototype
  2. 使用Object.createA.prototype=Object.create(B.prototype)

转载地址:http://dflja.baihongyu.com/

你可能感兴趣的文章
[LintCode] Find the Missing Number [三种方法]
查看>>
elasticsearch搭建
查看>>
使用python解释设计模式[译]
查看>>
对立即数进行位移引发的小问题
查看>>
位置行业应用开发应该如何选择GPS定位系统
查看>>
Kubernetes核心概念总结
查看>>
如何用 CSS 和 D3 创作火焰动画
查看>>
详解K8S与Rancher 2.0内的身份认证与授权
查看>>
MyEclipse8.6配置Maven
查看>>
5G背后那些你不知道的事儿,一对一直播app源码加速系列 ...
查看>>
WPF 控件自定义背景
查看>>
年终盘点丨细数2018云栖社区12大热点话题
查看>>
Python零基础学习代码实践 —— 打印5位数的回文数并统计个数 ...
查看>>
联想手机首发高通旗舰处理器骁龙855,能否借此打出一场翻身仗? ...
查看>>
阿里云MVP:阿里云高可用架构的设计
查看>>
Linux基础命令---文本显示look
查看>>
图数据库HGraphDB介绍
查看>>
互联网装修O2O模式是否可行?
查看>>
在Linux上安装Git
查看>>
揭开数据库RPO等于0的秘密(下)
查看>>