这是我参与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
protpptye
prototype -- 显示原型,在js中每个函数都有这个属性。这个属性指向一个对象,这个对象就称为原型对象。这个原型对象中默认有一个constructor属性又指回这个函数本身(类似套娃),我找了一张图片方便大家理解
那么这个原型对象有什么作用呢?
简单来说,我们可以往这个原型对象上添加一些自定义的方法,这样通过该函数new出来的实例对象就可以直接用这些方法了,不用自己在去写了。举个🌰
当我们在MDN这个网站上搜索数组方法的时候,我们可以看到
它把数组的方法全部定义在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__)
这个隐式原型的的作用简单来说就是查找属性,当我们查找对象中的某个属性的时候,首先会在对象自身查找,如果找到则返回,如果找不到则会查找__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的原型。这个更加绕,这里就不多说了。
如果我还肝的动,我们下期再见👋