Vue2数据响应式原理深度解析( 一 )
Vue2数据响应式原理逻辑深度解析(一)
前言
各位小伙伴们大家好呀,最近看到很多朋友在面试的时候被问及vue2中的数据响应式原理的时候,能够提到Object.defineProperty中的setter函数和getter函数,在说出它们的作用后就浅尝辄止,并不能理解较深层面的逻辑嵌套。因此本人开始执笔这vue2响应式原理解析的专栏,帮大家从源码逻辑层面梳理其中的相关实现。
家人们做好准备哦,相信各位JS的基础都不错,关于细节方面本系列应提尽提,不客气哈哈哈~
Object.defineProperty
相信这个方法各位都不陌生,它能为一个新对象设置属性,其中内部的getter函数和setter函数能够迅速捕捉用户对于数据的操作并触发相应的函数,这一现象被称为 '数据劫持'
废话不多说,直接上图
代码
let obj = { }
Object.defineProperty(obj, 'a', {
get() {
console.log(`您正在视图查看obj的a属性`)
return 9
},
set() {
console.log(`您正在视图修改obj的a属性`)
}
})
console.log(obj.a)
可以看到我们最初定义了一个obj空对象,并利用Object.defineProperty中的get方法为其设定了一个键值对,键为a,因此对于属性a的操作会被监视; 而其对应的值是我们给其内部get函数设置的返回值,值为9
此时我们来打印obj里的a属性,来看控制台
那这里的get( )函数捕捉到了我们想要打印这个被监视的属性a的值这个操作,最终执行并触发自己内部的代码,肥肠好~
此时我们现在在外部修改obj.a的值,如图
来看控制台的反应
这时set( )函数也捕捉到了我们想修改这个被监视的属性a的值变为10,并也触发了这个函数本身,没毛病~
那如果此时小伙伴们再次打印obj . a的值,发现a的值居然还是原来get函数的返回值9,这是为什么??我们不是改成10了吗?原来a的值只能由get函数的返回值决定,不论外部做什么操作,都无法直接影响到a本身的,此时我们就需要创建一个函数,传相关的参数进去,间接去影响get函数的返回值,说到这里,相信大家都有点感觉了
修改对象内部属性的值
这里我们创建一个defineReactive函数,其接收三个参数,对象data,要监视的值key,以及设置的值val,再把我们刚刚的Object.defineProperty()函数放入内部,而它也要接收上面传递过来的参数,再在这个函数内部完成变量的一些简单周转,如图
代码
function defineReactive(data, key, val) {
Object.defineProperty(data, key, {
get() {
console.log(`您正在视图查看obj的${key}属性`)
return val
},
set(newVal) {
console.log(`您正在视图修改obj的${key}属性`)
val = newVal
}
})
}
在这里,defineReactive函数接收的data和和key不用多说,而属性值val会传递给下面的Object.defineProperty()函数,val会在内部进行一些周转,最终使得get函数的返回值就为传递进来的这个val,这是函数闭包的一个实现,相信大家不会对此表示陌生
此时我们来调用这个defineReactive函数
打印结果
这样一来起来我们就通过外部的操作影响到了get函数的返回值,也就是设置了a的值
此时我们在外面设置a的值能否直接生效呢?如图
当给被监视的对象a,直接设置属性值时,会触发Object.defineProperty()函数内部的set函数,它接收这个即将修改的值666, 并传递给val,因此上面的get函数的返回值也是666,因此这时候就成功修改了属性a的值
打印结果
可以看到结果打印正确,奈斯~
思考
那么问题来了,如果此时我这样 把obj设置成如下
再次调用defineReactive函数
注意此时我们传递进来的只有两个参数obj和 'a'
并打印obj最里面的c
打印结果
可以看到这只触发了get关于a的函数,但为什么没打印出 您正在试图查看c属性
呢?
也就是说我们现在只是给了obj对象本身绑定了数据劫持,而其内部的属性并没有绑定数据劫持, 这显然不正常。因此这里需要我们规范的去书写自己的逻辑代码,来给对象内部的属性都绑定上响应式数据,关于如何去开展接下来的绑定数据劫持的操作,我们在下一篇章中正式开始手写自己的逻辑代码
注意:本系列需要大量的运用到模块式编写,因此涉及到多层文件相互引用嵌套,请各位先熟悉其相关知识,更有助于后期的理解
总结
这节课我们完成了关于 Object.defineProperty( )函数的运用,复盘了关于get( )和set( )的功能,并最后利用了defineReactive函数实现了直接在外部修改属性值的操作,今天的文章只是基础部分,后期文章难度系数会逐渐增大,请各位做好心理准备
本节代码
index.js
let obj = {
a: {
b: {
c: 555
}
}
}
function defineReactive(data, key, val) {
if (arguments.length === 2) {
val = obj[key]
}
Object.defineProperty(data, key, {
get() {
console.log(`您正在视图查看obj的${key}属性`)
return val
},
set(newVal) {
console.log(`您正在视图修改obj的${key}属性`)
val = newVal
}
})
}
defineReactive(obj, 'a')
console.log(obj.a.b.c)
转载自:https://juejin.cn/post/7165438007204380702