深入浅出JS原型&原型链

227 阅读4分钟

这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战

xdm,最近无聊在看vue的源码解析,发现在vue的实例对象vm与vue组件的实例对象vueComponent这部分的实现就是用了原型与原型链相关的知识点。虽然源码分析起来是真的难(我也没咋看懂)。但好在js原型与原型链这部分我自认为还是比较熟悉的。下面我就简单聊聊我对原型与原型链的理解!

既然是深入浅出,我先引出一个比较绕的概念跟我画的一张图然后我们在慢慢分析(图中左侧为栈空间,右侧为堆空间,0xXXX为引用对象的地址值)

对象的隐式原型__proto__指向它构造函数的显示原型prototype

 function Fn() {
     this.a =1
 }

 Fn.prototype.b = 2

 let fn = new Fn()
 
 console.log(fn.a) //1
 console.log(fn.b) //2
 console.log(fn.c) //undefined
 console.log(fn.toString) //function

WeChat7fb0a9d7499811aece10eefc3b0c7b8c.png

protpptye

prototype -- 显示原型,在js中每个函数都有这个属性。这个属性指向一个对象,这个对象就称为原型对象。这个原型对象中默认有一个constructor属性又指回这个函数本身(类似套娃),我找了一张图片方便大家理解

WeChatfd5b2837ea3f0c4b15600ecbfcb7b241.png

那么这个原型对象有什么作用呢?
简单来说,我们可以往这个原型对象上添加一些自定义的方法,这样通过该函数new出来的实例对象就可以直接用这些方法了,不用自己在去写了。举个🌰

当我们在MDN这个网站上搜索数组方法的时候,我们可以看到

WeChat23bd62fc612d0be452fd06bef0634670.png 它把数组的方法全部定义在protptype属性上了,所以我们使用数组方法的时候直接拿来就能用还是非常方便的!

proto

proto -- 隐式原型,在js中每个对象都有这个属性。这个属性的值指向它的构造函数protptype的值

我们来验证一下

 function Fn() {
     this.a =1
 }

 Fn.prototype.b = 2

 let fn = new Fn()
 console.log(Fn.prototype)
 console.log(fn.__proto__)
 console.log(Fn.prototype===fn.__proto__)

WeChat02f7d71ba88f29c9a3b2be7be4fbb62d.png

这个隐式原型的的作用简单来说就是查找属性,当我们查找对象中的某个属性的时候,首先会在对象自身查找,如果找到则返回,如果找不到则会查找__protp__这条线,再去该对象的构造函数的prototype这个属性上去找,如果找到则返回结果,如果没有找到则继续沿着prototype的__protp__去找(显示原型对象也是对象,所以也会有__proto__这条线)...以此类推,当然这个无限套娃的过程也是有终点的,直到查找到Object的protptype的__protp__为null,这个查找的过程也就是原型链

我们回过头来分析一下开头的代码与图片

function Fn() {this.a = 1}
首先我们创建了一个构造函数Fn,他的地址值为0x123

Fn.prototype.b = 2
我们说过函数中有个prototype属性,我们可以在这个原型对象上自定义我们自己的属性 我们这里在原型上新增一个属性b值为2 ,这个原型对象的地址值为0x234
let fn = new Fn()
fn对象为Fn函数的实例,既然是对象,那么他的隐式原型一定会指向他构造函数的显示原型,所以实例对象的__proto__的值一定为0x234

    console.log(fn.a) //1 
    console.log(fn.b) //2
    console.log(fn.c) //undefined 
    console.log(fn.toString) //function

Ok,我们在看这4个输出,前两个就不说了,比较简单。先来看第三个输出undefined,实例对象fn中本身没有c这个属性,于是沿着他的隐式原型继续向上找,原型对象中也没有c这个属性,继续向上查找,直到查找到Object的原型对象,依旧没有属性c,所以返回undefined

第四个输出为什么是一个函数呢?因为toString这个方法属于对象的内置方法,是js引擎帮我们定义在Object这个构造函数的原型上的,所以即使我们不自己定义这个方法,我们依然可以拿到它!!

Ok,原型与原型链就更到这里。我感觉掌握这些足以应付面试或者看一些原型相关的源码。有兴趣的小伙伴可以自行研究一下Function的原型。这个更加绕,这里就不多说了。

如果我还肝的动,我们下期再见👋