vue3-proxy

7/18/2020 vue3

Object.defineProperty的缺点

  • 深度监听需要一次性递归
  • 无法监听新增属性/删除属性(Vue.set Vue.delete)
  • 无法原生监听数组,需要特殊处理

# Proxy实现响应式

  • 深度监听、性能更好
  • 可监听新增/删除属性
  • 可监听数组变化
  • Proxy 能规避Object.defineProperty的问题
  • Proxy 无法兼容所有浏览器,无法监听 Polyfill

# Proxy 实现


/**
 * 参数1 target: Proxy包装的目标对象  任何类型的对象
 * 参数2 handler 各属性定义的函数执行操作
 * 
 */

// let data = {
//     a: 1,
//     b: 2,
// }

let data = [1,2,3,4]

const ProxyData = new Proxy(data, {
    // 获取 
    /**
     * 
     * @param {*} target 目标对象
     * @param {*} property 被获取的属性名 理解为key
     * @param {*} receiver Proxy 或者继承 Proxy 的对象
     * return 可以返回任何值
     */
    get(target, property, receiver) {

        /**
         * target 需要取值的目标对象
         * property 需要获取的值的键值
         * receiver 如果target对象中指定了getter,receiver则为getter调用时的this值。
         * return 属性的值
         */
        const result = Reflect.get(target, property, receiver)
        console.log('get', result);
        return result
    },
    // 设置
    /**
     * 
     * @param {*} target 目标对象
     * @param {*} property 将被设置的属性名  理解为key
     * @param {*} value 新属性值
     * @param {*} receiver 被调用的对象
     * return 会返回一个布尔值
     */
    set(target, property, value, receiver) {
        /**
         * target 设置属性的目标对象
         * property 设置的属性的名称
         * value 设置的值
         * receiver 如果遇到 setter,receiver则为setter调用时的this值。
         * return 返回一个 Boolean 值表明是否成功设置属性。
         */
        const result = Reflect.set(target, property, value, receiver)
        console.log('set', property, value);
        return result

    },
    // 删除
    /**
     * 
     * @param {*} target 目标对象
     * @param {*} property 待删除的属性名
     * return 必须返回一个布尔值,表示该属性是否被成功删除
     */
    deleteProperty(target, property) {

        /**
         * target 删除属性的目标对象
         * property 需要删除的属性的名称
         * return Boolean 值表明该属性是否被成功删除。
         */
        const result = Reflect.deleteProperty(target, property)
        console.log('delete', property);
        return result
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75

# Proxy响应式实现


// 创建响应式
function reactive(target = {}) {
    // 对象或数组, 不是对象或数组,返回
    if (typeof target !== 'object' || target == null) {
        return target
    }

    // 代理proxy配置
    const proxyConfig = {
        get(target, key, receiver) {

            const result = Reflect.get(target, key, receiver)
            console.log('get', result);

            // 深度监听,获取到的时候才执行, 
            // object.defienProperty 一次性执行
            return reactive(result)

        },
        set(target, key, value, receiver) {
            // 重复设置数据,不处理
            if(value === target[key]){
                return true // 默认设置成功
            }

            const ownkey = Reflect.ownKeys(target)
            if(ownkey.includes(key)){
                console.log('已存在', key);
            }else{
                console.log('新增', key);
            }


            const result = Reflect.set(target, key, value, receiver)
            console.log('set', key, value);
            return result // 是否设置成功
        },
        deleteProperty(target, key) {
            const result = Reflect.deleteProperty(target, key)
            console.log('deleteProperty', key);
            return result // 是否删除成功
        }
    }

    // 返回代理对象
    const observer = new Proxy(target, proxyConfig)
    return observer
}



// 数据
// const data = {
//     a: 1,
//     b: 2,
//     c: {
//         d:{
//             e:{
//                 f:{
//                     g:3
//                 }
//             }
//         }
//     }
// }

let data = [1,2,3,4,5]

const proxyData = reactive(data)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
更新: 7/25/2022, 3:15:19 PM