为什么Vue3.0使用Proxy实现数据监听(defineProperty表示不背这个锅)

2020-06-12 20:45:47易采站长站整理
进行劫持。

也正是因为这个原因,使用vue给

data
中的数组或对象新增属性时,需要使用
vm.$set
才能保证新增的属性也是响应式的。

下面看一下vue的

set
方法是如何实现的,
set
方法定义在
core/observer/index.js
,下面是核心代码。


/**
* Set a property on an object. Adds the new property and
* triggers change notification if the property doesn't
* already exist.
*/
export function set (target: Array<any> | Object, key: any, val: any): any {
// 如果target是数组,且key是有效的数组索引,会调用数组的splice方法,
// 我们上面说过,数组的splice方法会被重写,重写的方法中会手动Observe
// 所以vue的set方法,对于数组,就是直接调用重写splice方法
if (Array.isArray(target) && isValidArrayIndex(key)) {
target.length = Math.max(target.length, key)
target.splice(key, 1, val)
return val
}
// 对于对象,如果key本来就是对象中的属性,直接修改值就可以触发更新
if (key in target && !(key in Object.prototype)) {
target[key] = val
return val
}
// vue的响应式对象中都会添加了__ob__属性,所以可以根据是否有__ob__属性判断是否为响应式对象
const ob = (target: any).__ob__
// 如果不是响应式对象,直接赋值
if (!ob) {
target[key] = val
return val
}
// 调用defineReactive给数据添加了 getter 和 setter,
// 所以vue的set方法,对于响应式的对象,就会调用defineReactive重新定义响应式对象,defineReactive 函数
defineReactive(ob.value, key, val)
ob.dep.notify()
return val
}

set
方法中,对
target
是数组和对象做了分别的处理,
target
是数组时,会调用重写过的
splice
方法进行手动
Observe

对于对象,如果

key
本来就是对象的属性,则直接修改值触发更新,否则调用
defineReactive
方法重新定义响应式对象。

如果采用

proxy
实现,
Proxy
通过
set(target, propKey, value, receiver)
拦截对象属性的设置,是可以拦截到对象的新增属性的。