Proxy 深度探索:一级代理与多层级代理对象的实现

7 篇文章 1 订阅

在前端开发中,Proxy 对象用于定义基本操作的自定义行为,如属性查找、赋值、枚举、函数调用等。它可以作为某些内置对象的包装器,例如,对数组或函数的包装。今天,我们将深入探索 Proxy 的应用,并演示如何实现一级代理和多层级代理对象。

一级代理的简单实现

首先,我们来看一个简单的 Proxy 实现。在 TypeScript 中,Proxy 对象是这样创建的:

const proxy = new Proxy({}, {
    get(target, key, receiver) {
        return Reflect.get(target, key, receiver);
    },
    set(target, key, value, receiver) {
        return Reflect.set(target, key, value, receiver);
    }
})

在上述代码中,我们创建了一个空的 Proxy 对象,并定义了 get 和 set 陷阱函数。这些陷阱函数允许我们在访问或修改 Proxy 对象的属性时,执行自定义的操作。

代理的简单应用例子

接下来,我们通过一个简单的例子来展示 Proxy 的应用。假设我们有一个用户信息对象 userInfo,我们希望通过 Proxy 对象实现属性的间接访问和修改。

// 源数据
        let userInfo = {
            name: '张三',
            age: 18,
            sex: '男'
        }
        // 映射关系
        const userMap = {
            uid_1: 'name',
            uid_2: 'age',
            uid_3: 'sex',
        }
        // 代理
        const userProxy = new Proxy(userInfo, {
            get(target, key, receiver) {
                return Reflect.get(target, userMap[key], receiver);
            },
            set(target, key, value, receiver) {
                return Reflect.set(target, userMap[key], value, receiver);
            }
        })
        userProxy['uid_1'] = '李四';
        console.log(userInfo.name); // 李四
        console.log(userProxy['uid_2']); // 18

在这个例子中,我们创建了一个 userProxy 对象,它代理了 userInfo 对象。通过 userMap 映射关系,我们可以使用 uid_1、uid_2、uid_3 这样的键来间接访问和修改 userInfo 对象的属性。

多层级代理对象的实现

在实际应用中,我们可能需要处理更复杂的对象结构,如嵌套对象或数组。这时,我们可以使用递归的方式来实现多层级代理对象。

以下是一个处理多层级代理对象的例子:

 const data = {
            age: 55,
            'dync_-2': '我是',
            extra: {
                name: 2,
            },
            refs: {
                abc: 'xxx'
            }
        }
        const pathObj: any = {
            uid_1: 'age',
            uid_2: 'extra.name',
            uid_3: 'refs.abc',
        }
        const formData = reactive(onlyReactive(data))
 /* 
        自定义onlyReactive
        */
        function onlyReactive(target: any) {
            // 判断是否是对象:
            if (target && typeof target === 'object' && !Array.isArray(target)) {
                Object.keys(target).forEach(key => {
                    target[key] = onlyReactive(target[key])
                })
                const proxy = new Proxy(target, {
                    // _map: new WeakMap(), // 用来保存数据的内部属性
                    get(target, key: string, receiver) {
                        if (typeof key === 'string' && pathObj.hasOwnProperty(key) && key.indexOf('uid_') != -1) {
                            const parts = pathObj[key].split('.');
                            console.log(parts);
                            if (parts.length <= 1) {
                                return target[pathObj[key]];
                            }
                            let current = target
                            for (let i = 0; i < parts.length; i++) {
                                if (current[parts[i]] !== undefined) {
                                    // current = Reflect.get(current, parts[i]);;
                                    current = current[parts[i]];
                                } else {
                                    return undefined; // 如果路径中的任何部分不存在,则返回undefined  
                                }
                            }
                            return current;
                        } else {
                            return Reflect.get(target, key, receiver);
                        }
                    },
                    set(target, key: string, value, receiver) {
                        if (key in pathObj) {
                            // 获取路径  
                            const path = pathObj[key];
                            // 设置嵌套属性值  
                            console.log('path', path);
                            if (path.indexOf('refs') == -1) {
                                setValueByPath(target, path, value);
                            } else {
                                console.warn('只读的, 不能修改')
                            }
                            return true; // 表示设置成功  
                        }
                        if (key.indexOf('dync_') != -1) {
                            console.warn('只读的, 不能修改')
                            return true;
                        }
                        // 如果不是通过pathObj来设置的属性,则直接设置  
                        return Reflect.set(target, key, value, receiver);
                    },
                    // deleteProperty(target: any, key: any, receiver: any) {
                    //     console.warn('只读的, 不能删除')
                    //     return true
                    // },
                })
                return proxy
            }

            return target
        }
        // 辅助函数,用于通过路径设置值  
        function setValueByPath(obj: any, path: string, value: any) {
            const pathArray = path.split('.');
            let currentObj = obj;
            const lastKey: any = pathArray.pop();
            for (let i = 0; i < pathArray.length; i++) {
                const key = pathArray[i];
                if (!(key in currentObj)) {
                    currentObj[key] = {}; // 如果属性不存在,则创建它  
                }
                currentObj = currentObj[key];
            }
            currentObj[lastKey] = value; // 设置最终的值  
        }

在这个例子中,我们定义了一个 onlyReactive 函数,它接受一个目标对象作为参数,并返回一个新的 Proxy 对象。在 Proxy 的 get 陷阱函数中,我们根据 pathObj 映射关系处理多层级属性的访问。如果属性不存在,我们返回 undefined

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值