JS的原型链
文章目录
前言
在使用数组或对象中的方法时,你是不是会感觉很奇怪,为什么仅仅是创建了一个数组或是对象,就能够使用它提供的方法呢?JS是怎么做到的呢?原因很简单,因为这些方法早就被定义在数组或对象的构造函数的原型上了,接下来,本篇文章就将着重讲解JS原型和原型链的相关知识。
一、原型是什么?
JS中,每一个函数都有自己的原型对象,这个对象会存放一些属性和方法。这个函数上会有一个prototype属性指向这个原型对象;同时,通过这个函数创建的实例对象身上都会有一个名叫__proto__的属性也指向这个原型对象。如下图所示:
正是因为这样的关系,所以当你使用实例上的方法或属性时,js会先从这个实例身上找,找到了对应的方法或者属性则直接调用或者返回,而如果找不到,js就会顺着__proto__这条线找到当前实例构造函数的原型上面,看这个对象身上有没有使用的方法或属性,如果有则使用原型上的属性和方法。
二、原型链
先看一张图
原型链本质就是原型关系的拓展,就像之前说的,原型本质就是一个对象,而任何对象都是Object这个构造函数的实例,因此当一个实例
众所周知,在JavaScript中,函数也是一种特殊的对象,因此任何通过构造函数创建的实例都可以找到Object这个构造函数的原型,从而使用它上面的方法,这里举一个例子
我在Object的原型上创建了一个叫sayHaHa的方法,并且用一个空对象执行这个方法,发现执行时并未报错,原因就是在obj这个空对象身上找不到sayHaHa这个方法,就去它的构造函数的原型身上找,此时发现Object的原型身上有这个方法,于是调用了这个方法。
这也解释了前言中的问题,当的使用对象或数组中的方法时,在对象和数组身上找不到对应的方法,于是js顺着__proto__这条线找到了它们的构造函数也就是Function和Object的原型上,而原型上是有这些方法的。
而原型链有一个特定,就是依次查找,首先在实例身上找,找到了直接调用,找不到就顺着__proto__去它的构造函数的原型上找,找到了就调用,还没找到就顺着构造函数原型对象的__proto__属性继续向上查找,直到找到为止;但就像上图所示,在JavaScript中,任何实例顺着原型链都会最终查找的Object的原型上,因此JS将Object构造函数的原型上的__proto__指向了null作为原型链的终点,当查到了null之后如果还没查到就会报错,提示找不到。
这就是JS中原型链的相关概念,活用原型链可以给我们代码开发提供很多便利,最典型的就是数组和对象原型链上提供的各种方法,另外vue2中全局事件总线也是通过向Vue的原型上注入$bus对象,再给这个对象上增加属性和方法从而达成组件间相互传参的。
总结
JS的原型主要是用于扩展实例对象身上的属性和方法,让同一个构造函数下的实例都能够使用这些新增加的属性或方法。调用属性或方法的方式就是顺着原型链一层一层向上查,直到找到对应的属性和方法(找到就返回或调用),或者找到了原型链的尽头null提示报错信息:XXX不存在。