• Proxy是怎么做数据劫持的


    概述

    Vue3的一个重大升级就是使用 proxy 来做数据劫持,我们来体验一下用 proxy 是怎么做数据劫持的,供以后工作时参考,相信对其它人也有用。

    Vue2.x的缺点

    Vue2.x是使用Object.defineProperty来做数据劫持的,但是它有以下三个缺点:

    1.不能劫持数组的变化,需要做特殊处理(通过劫持数组的push、splice等方法实现的)
    2.必须深度遍历对象的每个属性
    3.无法监听属性的新增和删除操作(通过Vue.set 和 Vue.delete实现的)
    

    使用 proxy

    1.劫持数组的变化

    const test = [];
    const testProxy = new Proxy(test, {
        get(target, key) {
            if (key !== 'length') {
                console.log('get==================', target, key);
            }
    
            return target[key];
        },
        set(target, key, value) {
            if (key !== 'length') {
                console.log('set==================', target, key);
            }
    
            return Reflect.set(target, key, value);
        }
    });
    
    testProxy.push(1);
    testProxy[0] = 2;
    testProxy[1] = 'abc';
    

    这里需要注意的是,这里使用push的时候,length属性会发生变化,所以上面过滤掉了length属性。(当然我这里做的比较简单,而 Vue3 源码里面是通过判断 push、indexOf、shift 等方法来分情况做的。)

    2.必须深度遍历对象的每个属性

    const toProxy = new WeakMap();
    const toRaw = new WeakMap();
    const isObject = val => typeof val === 'object' && val !== null;
    const proxyConfig = {
        get(target, key) {
            const res = Reflect.get(target, key);
            if (isObject(res)) {
                return reactive(res);
            }
    
            console.log('get==================', target, key);
            return res;
        },
        set(target, key, value) {
            console.log('set==================', target, key);
            return Reflect.set(target, key, value);
        }
    }
    
    function reactive(target) {
        const res = toProxy.get(target);
    
        if (res) {
            return res;
        }
    
        if (toRaw.get(target)) {
            return target;
        }
    
        const observed = new Proxy(target, proxyConfig);
        toProxy.set(target, observed);
        toRaw.set(observed, target);
        return observed;
    }
    
    const test = {
        a: 2,
        b: {
            c: 'abc',
        }
    };
    const testProxy = reactive(test);
    console.log(testProxy.b.c);
    testProxy.b.d = 3;
    

    这里需要注意的是,当属性是深度嵌套的时候,只会触发 getter,并不会触发setter,所以需要对深度嵌套的属性进一步使用 proxy!

    但是使用 proxy 得到的新属性又不能挂载到对象上面去,所以需要使用一个 weakmap 储存起来,同时也能加快查找速度。

    3.监听属性的新增和删除操作

    const test = {a:2};
    const testProxy = new Proxy(test, {
        deleteProperty(target, key) {
            console.log('delete==================', target, key);
            delete target[key];
        },
    });
    
    delete testProxy.a;
    

    总结

    1.proxy做数据劫持还是有一些痛点的,比如对于数组的push、unshift等方法需要做兼容,对于对象的深层属性仍然需要通过遍历来重新proxy。

    2.proxy的功能不止如此,它还能拦截更多的属性,比如 has、defineProperty、apply 等。

  • 相关阅读:
    修改Linux中的用户名
    阿里云服务器安全设置
    【solr专题之二】配置文件:solr.xml solrConfig.xml schema.xml
    【solr专题之四】关于VelocityResponseWriter
    django概述
    从烙铁手到IT男
    docker安装
    redhat之数据挖掘R语言软件及rstudio-server服务的安装
    分享一下 aix安装python提示C编译器问题的办法
    Android 播放Gif 动画
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/13772074.html
Copyright © 2020-2023  润新知