问:前端中的原型链(Prototype Chain)是何物?
前言
我们在项目的开发、面试的过程中,我们都在接触原型及原型链,这里这样说大家没有印象。各位朋友在vue 2中做全局挂载,这个做过吧。
1 | Vue.protype.$xx = xx |
上面这个代码是不是很熟悉?没错,上面的代码就是我们在vue 2中做全局挂载的一种方式。这个就是一个原型的操作。那这个也只是一个原型操作啊,那什么是原型链,你还是没说啊,ei,让我们往看下面。一起来揭开原型链的神秘面纱。
什么是原型链(Prototype chain)?
什么是原型链?我们谈原型链的时候,继承它就跑不脱(跑不掉),它跟原型链是挂钩的,二者并存的一个关系。
我们看一下MDN的官方解释。
每个实例对象(
object)都有一个私有属性(称之为__proto__)指向它的构造函数的原型对象(prototype)。该原型对象也有一个自己的原型对象(__proto__),层层向上直到一个对象的原型对象为null。并作为这个原型链中的最后一个环节。
大白话就是说我们每一个对象都有一个私有属性__proto__,层层向上的一个__proto__的一个链就是原型链。
我们看张图。
我们再画张图看一下他们的存在关系。
上图中的__proto__的一个继承过程,形成了一个链,而这个链就是常说的原型链。
那什么又是继承呢?我们看下面。
什么是继承(inherit)?
继承这个很好解释,我们这里就不用MDN的官方解释了。直接上大白话解释。张三将ta的东西传承给ta的儿子张四,这样的一个过程就叫做继承。
让我们开始来看代码案例
让我们一起来看代码案例,相信朋友你看完你就懂了,他人再问不再百度/沉思。
object对象的原型及原型链
我们先来创建一个对象(Object),看看它自身的原型及原型链。
1 |
|
我们发现它的原型上有一个__proto__为null,这一个继承自Object,再加上它自己又一个__proto__,所以它的原型链有两层,由此我们得到以下结论。
obj的原型链有两层。Object为原型链上的顶层。
那构造函数和class类的原型是不是也是这样呢?下面让我们一起来看看。
构造函数和class类的原型
构造函数
我们先一起来看构造函数中的原型及原型链。
1 |
|
我们根据我们的打印结果和上面的图片发现构造函数它有三层,这是为啥呢?
解答:
因为构造函数它本身就存在一个原型实例,然后我们new进行实例的时候,我们得到的是这个被实例化的构造函数,它又继承了构造函数的原型,所以它就存在三层。我们看一下未被实例的构造函数。
1 |
|
我们发现我们打印出来它的原型上,就只存在两层。这就验证了我们刚刚说的话。
class类
我们看看class类中的原型链长啥样。
未被new实例化
1 |
|
new实例化后的
1 |
|
我们发现class和构造函数在未实例化和实例化都是一样的。它俩明明都不是同一个东西,为啥为是一样的呢?
我们想要搞清楚这个问题,我们就需要知道class是这个啥,为啥原型链都是一样的。
class解读:
class是ES2015/ES6中新增的语法糖,其本质上也是一个构造函数,只是方便我们用class关键字进行使用罢了。
原型链深入了解及进阶
下面我们将进行实战使用。系好安全带开始发车了。
案例一:
1 |
|
问:打印出来的obj.name是什么?
答案:’张三’
解读:
这里我们在__proto__的上添加了一个name的键值对,然后我们修改了obj的原型为info的原型。
我们并没有在info中创建name的键值对,然后obj在它自身没有找不到,它就去它的上层原型上进行查找,找到了就给我们返回出来,如果没找到就是undefined。我们可以验证一下。
1 |
|
案例二:
1 |
|
问:obj的__proto__是啥?
答案:Object
❓❓❓我们刚刚不是对它的__proto__进行更改了吗。它为啥还是Object,你肯定在骗我,我们看图。
解答:
__proto__不允许修改为非对象(Object)。在我们修改的时候就给我们拦截了,所以我们根本就没有修改到。
案例三
1 |
|
问:obj的__proto__是啥?
答案:No properties
❓❓❓我们刚刚不是对它的__proto__进行更改为null吗。它为啥是No properties,你肯定在骗我,我们看图。
解答:
null的类型为object,所以它是可以修改成功的。以至于null的类型为啥是object,这则是因为js遗存下来的一个bug,而null本身是啥也没有的,所以它就会变成图上的那样。
案例四:
1 |
|
问:打印出来的obj.name是什么?
答案:’李四’
解读:
这里的原理和案例一是一样的,我们的info是Object类型,所以可以修改成功。
原型链的副作用
在我们操作原型及原型链的过程中,如果原型上不存在我们需要的属性,就会一直在原型链上查找该属性,这是一个比较耗时过程,直至找到或者找不到才会结束查找。
总结
在我们更深一步了解javascript的过程中,了解及掌握原型和原型链是一步必走的路。说句题外话,这东西有时候真的好绕😭。
本篇文章存在错误或不足之处,还请各位朋友指出并进行评论留言。
