一文详解如何用原型链的方式实现JS继承_第1页
一文详解如何用原型链的方式实现JS继承_第2页
一文详解如何用原型链的方式实现JS继承_第3页
一文详解如何用原型链的方式实现JS继承_第4页
一文详解如何用原型链的方式实现JS继承_第5页
已阅读5页,还剩1页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第一文详解如何用原型链的方式实现JS继承目录原型链是什么通过构造函数创建实例对象用原型链的方式实现继承方法1:Object.create方法2:直接修改[[prototype]]方法3:使用父类的实例总结今天讲一道经典的原型链面试题。

原型链是什么

JavaScript中,每当创建一个对象,都会给这个对象提供一个内置对象[[Prototype]]。这个对象就是原型对象,[[Prototype]]的层层嵌套就形成了原型链。

当我们访问一个对象的属性时,如果自身没有,就会通过原型链向上追溯,找到第一个存在该属性原型对象,取出对应值。

当然原型链不是无止境的,和单链表一样,最后一个原型对象的值是null,原型链的所有对象都找不到指定的属性时,我们会拿到undefined。

[[Prototype]]虽然无法通过脚本进行访问,但大多数浏览器提供了__proto__属性来访问这个内置对象,但它并不是标准,无法兼容所有浏览器。

下面来举几个例子,让读者对原型链有一个直观的认识:

通过对象字面量声明a={}时,a的[[prototype]]就是Ototype。此时的原型链是:a-Ototype-null。这里有个易错点,就是以为a的上一个原型对象是Object,其实并不对,Object其实只是一个构造函数。声明数组arr=[1,2,4],它的原型链则是arr-Atotype-Ototype-null。Object.create(null)甚至能够创建一个连[[prototype]]都没有的真正的空对象,一般用于做字符串哈希表,比如vue源码里就能经常看到。

通过构造函数创建实例对象

在JavaScript中,一个函数会在new关键字的配合下成为构造函数。也就是说,任何一个函数都可以成为构造函数。

当声明一个构造函数时,它会有一个属性名为prototype的对象(和[[prototype]]是不同的东西),这个对象就是原型对象。这个对象的constructor又反过来指向构造函数。

当我们对使用new关键字创建对象,被创建的对象的[[prototype]]会指向这个prototype。

functionRect(){}

constrect=newRect()

rect.__proto__===Rtotype//true

Rtotype.constructor===Rect//true

只要是通过newRect()创建的对象,无论多少次,它的[[prototype]]都是指向Rtotype。另外,Rtotype指向的是Ototype。

这样,通过给构造函数的原型对象(Rtotype)添加一些方法(如Rtotype.draw),就能让创建的多个实例对象共享同一个方法,减少内存的使用。

用原型链的方式实现继承

理解了构造函数如何影响创建的实例的原型链后,我们来探讨一下核心问题,如何使用原型链来实现继承。

假设我们有一个Shape构造函数(父类)和Rect构造函数(子类)。代码如下:

//父类

functionShape(){}

Stotype.draw=function(){

console.log('ShapeDraw')

Stotype.clear=function(){

console.log('ShapeClear')

//子类

functionRect(){}

实现继承的代码放这里

Rtotype.draw=function(){

console.log('RectDraw')

}

通过前面的学习,我们知道,正常情况下使用newRect创建的实例对象,它的原型链是这样的:

rect-Rtotype-Otoype-null

现在我们要实现的继承,其实就是在原型链中间再加一个原型对象Stotype。对此我们需要对Rtotype进行特殊的处理。

方法1:Object.create

Rtotype=Object.create(Stotype)

Rtotype.constructor=Rect//选用,如果要用到constructor

Rtotype.constructor=Rect//选用,如果要用到constructor

Object.create(proto)是个神奇的方法,它能够创建一个空对象,并设置它的[[prototype]]为传入的对象。

因为我们无法通过代码的方式给[[prototype]]属性赋值,所以使用了Object.create方法作为替代。

因为Rtotype指向了另一个新的对象,所以把constructor给丢失了,可以考虑把它放回来,如果你要用到的话。

缺点是替换掉了原来的对象。

方法2:直接修改[[prototype]]

如果就是不想使用新对象,只想修改原对象,可以使用废弃的__proto__属性,但不推荐。

不过另外还有一个方法Object.setPrototypeOf()可以修改对象的[[prototype]],但因为性能的问题,也不推荐使用。

Object.setPrototypeOf(Rtotype,Stotype)

//或

Rtotype.__proto__=Stotype

都不推荐使用,但确实能用。

方法3:使用父类的实例

Rtotype=newShape()

形成的原型链为:

rect-shape(替代掉原来的Rtotype)-Stotype-Ototype-null

基本能用,缺点是会产生副作用,就是执行newShap()可能会出现副作用,比如给创建的对象添加了一些属性、发送了请求之类的,完全取决于构造函数内的代码。

某种意义上,这个缺点是致命的。不推荐使用。

总结

用原型链的方式实现一个JS继承,其实就是希望构造函数Son创建出来的对象son,它的原型链上加上父类Ptotype,所以最后就是要修改Stotype的[[prototype]]。

鉴于性能、兼容性、副作用等考虑,推荐使用方法1,即通过Object.create(Ptotype)创建一个指定了[[prototype]]的新对象,替换掉原来的Stotype指向的对象。

总结几个核心知识点:

任何对象都有[[prototype]]属性,读写对象属性发现当前对象不存在时,会访问[[prototype]]指向的对象尝试访问属性,于是原型链形成了。函数创建时,它的prototype属性会拿到一个原型对象。当函

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论