跳到主要内容

Vue3 用 Proxy 实现响应式

Proxy 实现响应式

  • 深度监听,性能更好
  • 可监听 新增/删除属性
  • 可监听数组变化
  • 但,无法兼容所有浏览器,无法 polyfill
// 创建响应式
function reactive(target = {}) {
if (typeof target !== 'object' || target == null) {
// 不是对象或数组,则返回
return target
}
// 代理配置
const proxyConf = {
get(target, key, receiver) {
// 改进
// 只处理本身(非原型的)属性
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('get', key) // 监听
}
const result = Reflect.get(target, key, receiver)
// return result // 返回结果
// 深度监听,把上面修改成下面
return reactive(result);
// 那么性能是如何提升?
/**
* Object.defineProperty 一次性递归完
* Proxy 是 get 到哪一层,就递归到哪一层
*/
},
set(target, key, val, receiver) {
// 改进
// 重复的数据,不处理
if (val === target[key]) {
return true
}
const ownKeys = Reflect.ownKeys(target)
if (ownKeys.includes(key)) {
console.log('已有的 key', key)
}else{
console.log('新增的 key', key)
}
const result = Reflect.set(target, key, val, receiver)
console.log('set', key, val)
console.log('result', result)
return result // 是否设置成功
},
deleteProperty(target, key) {
const result = Reflect.deleteProperty(target, key)
console.log('delete property', key)
console.log('result', result)
return result // 是否删除成功
}
}
// 生成代理对象
const observed = new Proxy(target, proxyConf)
return observed
}
// 测试数据
const data = {
name: 'zhangsan',
age: 20,
info: {
city: 'shenzhen',
a: {
b: {
c: {
d: {
e: 100
}
}
}
}
}
}
const proxyData = reactive(data);
// 测试
console.log(proxyData.age)
// get age
// 20
// 没有深度监听
console.log(proxyData.info.city)
// get info
// shenzhen
// 深度监听
console.log(proxyData.info.city)
// get info
// get city
// shenzhen
// 新增的 key
console.log(proxyData.age1=100)
// 新增的 key age1
// set age1 100
// result true
// 100

那么性能是如何提升?

  • Object.defineProperty 一次性递归完

  • Proxy 是 get 到哪一层,就递归到哪一层