Vue3.x改用Proxy替代Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,并且有多达13种拦截方法。并且作为新标准将受到浏览器厂商重点持续的性能优化。
Proxy只会代理对象的第一层,那么Vue3又是怎样处理这个问题的呢? 判断当前Reflect.get的返回值是否为Object,如果是则再通过reactive方法做代理, 这样就实现了深度观测。
监测数组的时候可能触发多次get/set,那么如何防止触发多次呢? 我们可以判断key是否为当前被代理对象target自身属性,也可以判断旧值与新值是否相等,只有满足以上两个条件之一时,才有可能执行trigger
- // 模拟 Vue 中的 data 选项
- let data = {
- msg: 'hello',
- count: 0
- }
- // 模拟 Vue 实例
- let vm = new Proxy(data, {
- // 当访问 vm 的成员会执行
- get (target, key) {
- console.log('get, key: ', key, target[key])
- return target[key]
- },
- // 当设置 vm 的成员会执行
- set (target, key, newValue) {
- console.log('set, key: ', key, newValue)
- if (target[key] === newValue) {
- return
- }
- target[key] = newValue
- document.querySelector('#app').textContent = target[key]
- }
- })
- // 测试
- vm.msg = 'Hello World'
- console.log(vm.msg)
复制代码
Proxy 相比于 defineProperty 的优势 Proxy 是 ES6 中新增的功能,可以用来自定义对象中的操作
- let p = new Proxy(target, handler);
- // `target` 代表需要添加代理的对象
- // `handler` 用来自定义对象中的操作
- // 可以很方便的使用 Proxy 来实现一个数据绑定和监听
- let onWatch = (obj, setBind, getLogger) => {
- let handler = {
- get(target, property, receiver) {
- getLogger(target, property)
- return Reflect.get(target, property, receiver);
- },
- set(target, property, value, receiver) {
- setBind(value);
- return Reflect.set(target, property, value);
- }
- };
- return new Proxy(obj, handler);
- };
- let obj = { a: 1 }
- let value
- let p = onWatch(obj, (v) => {
- value = v
- }, (target, property) => {
- console.log(`Get '${property}' = ${target[property]}`);
- })
- p.a = 2 // bind `value` to `2`
- p.a // -> Get 'a' = 2
复制代码
|