美文网首页
Proxy(vue响应式原理:数据侦测--数据劫持和数据代理)

Proxy(vue响应式原理:数据侦测--数据劫持和数据代理)

作者: 遇一顽石 | 来源:发表于2020-11-06 09:50 被阅读0次
  • 数据监测
  • 视图依赖数据收集
  • 数据变更通知更新视图

Object.defineProperty的缺陷

Object.defineProperty : 通过设定对象属性getter/setter方法来监听数据的变化,同时getter也用于依赖收集,而setter在数据变更时通知订阅者更新视图。

function defineReactive(obj, key, value) {
    observe(value) // 递归子属性
    Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get() {
            collectDeps() // 收集依赖
            return value
        },
        set(newVal) {
            observe(newVal); // 若是对象需要递归子属性
            if (newVal !== value) {
                notifyRender() // 通知订阅者更新
                value = newVal;
            }
        }
    })
}
function observe(obj) {
    if (!obj || typeof obj! === 'object') {
        return
    }
    Object.keys(obj).forEach(key => {
        defineReactive(obj, key, obj[key]);
    })
}
 
var data = {
    name: 'wonyun',
    sex: 'male'
}

1.无法检测到对象属性的新增或删除
由于js的动态性,可以为对象追加新的属性或者删除其中某个属性,这点对经过Object.defineProperty方法建立的响应式对象来说,只能追踪对象已有数据是否被修改,无法追踪新增属性和删除属性,这就需要另外处理。

Vue.set(obj, propertName/index, value)

2.不能监听数组的变化
vue在实现数组的响应式时,它使用了一些hack,把无法监听数组的情况通过重写数组的部分方法来实现响应式,这也只限制在数组的push/pop/shift/unshift/splice/sort/reverse七个方法,其他数组方法及数组的使用则无法检测到。

Proxy的使用

Proxy,字面意思是代理,是ES6提供的一个新的API,用于修改某些操作的默认行为,可以理解为在目标对象之前做一层拦截,外部所有的访问都必须通过这层拦截,通过这层拦截可以做很多事情,比如对数据进行过滤、修改或者收集信息之类。借用proxy的巧用的一幅图,它很形象的表达了Proxy的作用。

ES6原生提供的Proxy构造函数,用法如下:

var proxy = new Proxy(obj, handler)

其中obj为Proxy要拦截的对象,handler用来定制拦截的操作,返回一个新的代理对象proxy;Proxy代理特点:
1.Proxy的代理针对的是整个对象,而不是像Object.defineProperty针对某个属性。只需做一层代理就可以监听同级结构下的所有属性变化,包括新增属性和删除属性

2.Proxy也可以监听数组的变化

let handler = {
 get(target, key){
   if (target[key] === 'object' && target[key]!== null) {
     // 嵌套子对象也需要进行数据代理
     return new Proxy(target[key], hanlder)
   }
   collectDeps() // 收集依赖
   return Reflect.get(target, key)
 },
 set(target, key, value) {
   if (key === 'length') return true
   notifyRender() // 通知订阅者更新
   return Reflect.set(target, key, value);
 }
}
let proxy = new Proxy(data, handler);
proxy.age = 18 // 支持新增属性
let proxy1 = new Proxy({arr: []}, handler);
proxy1.arr[0] = 'proxy' 

参考:https://juejin.cn/post/6850418111985352711

相关文章

网友评论

      本文标题:Proxy(vue响应式原理:数据侦测--数据劫持和数据代理)

      本文链接:https://www.haomeiwen.com/subject/wgravktx.html