问:前端中的原型链(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
的过程中,了解及掌握原型
和原型链
是一步必走的路。说句题外话,这东西有时候真的好绕😭。
本篇文章存在错误或不足之处,还请各位朋友指出并进行评论留言。