• js代理(Proxy)和反射(Reflect)的应用


    跟踪属性访问

    const user = {
        name: 'Jack'
    }
    
    const userPorxy = new Proxy(user, {
        get(target, prop) {
            console.log(`Getting ${prop}`);
            return Reflect.get(...arguments);
        },
        set(target, prop, val) {
            console.log(`Setting ${prop} to ${val}`);
            return Reflect.set(...arguments);
        }
    });
    
    userPorxy.name;
    // Getting name
    userPorxy.name = 'Wango';
    // Setting name to Wango
    

    隐藏属性

    const user = {
        name: 'Wango',
        age: 24,
        addr: 'Chongqing, China',
        income: 'classified',
        email: 'example@mail.com'
    }
    
    const hiddenProps = ['addr', 'income', 'email'];
    
    const userProxy = new Proxy(user, {
        get(target, prop) {
            if (hiddenProps.includes(prop)) {
                return undefined;
            }
            return Reflect.get(...arguments);
        },
        has(target, prop) {
            if (hiddenProps.includes(prop)) {
                return false;
            }
            return Reflect.has(...arguments);
        }
    });
    
    console.log(userProxy.name); // Wango
    console.log(userProxy.addr); // undefined
    
    console.log('age' in userProxy); // true
    console.log('income' in userProxy); // false
    console.log('email' in userProxy); // false
    
    // 但是for...in依旧可以枚举属性
    for (let key in userProxy) {
        console.log(key);
    }
    

    属性验证

    const user = {
        name: 'Wango',
        age: 24
    }
    
    const userPorxy = new Proxy(user, {
        set(target, prop, val) {
            if (prop === 'age') {
                if (typeof val !== 'number') {
                    throw new TypeError('A number expected!');
                }
            }
            return Reflect.set(...arguments);
        }
    });
    
    userPorxy.age = 33;
    console.log(userPorxy.age); // 33
    userPorxy.age = '100'; // TypeError: A number expected!
    
    

    函数和构造函数参数验证

    function add(...args) {
        return args.reduce((a, b) => a + b);
    }
    
    const addProxy = new Proxy(add, {
        apply(target, thisArg, args) {
            for (let i = 0; i < args.length; i++) {
                if (typeof args[i] !== 'number') {
                    throw new TypeError('Non-number argument provided');
                }
            }
            return Reflect.apply(...arguments);
        }
    }); 
    
    console.log(addProxy(1, 2, 3, 4, 5)); // 15
    console.log(addProxy(1, 2, 3, 4, '5')); 
    // TypeError: Non-number argument provided
    
    class User {
        constructor(id) {
            this.id = id;
        }
    }
    
    const UserProxy = new Proxy(User, {
        construct(target, args, newTarget) {
            if (args[0] === undefined) {
                throw new Error('User cannot be instantiated without id');
            }
            return Reflect.construct(...arguments);
        }
    });
    
    const u1 = new UserProxy('Wango');
    const u2 = new UserProxy(); 
    // Error: User cannot be instantiated without id
    

    数据绑定与可观察对象

    被代理的类绑定到一个全局实例集合,让所有创建的实例都被添加到这个集合中

    
    const userList = [];
    
    class User {
        constructor(name) {
            this.name = name;
        }
    }
    
    const UserProxy = new Proxy(User, {
        construct() {
            const newUser = Reflect.construct(...arguments);
            userList.push(newUser);
            return newUser;
        }
    });
    
    new UserProxy('Wango');
    new UserProxy('Jack');
    new UserProxy('Lily');
    
    console.log(userList);
    // [User, User, User]
    

    把集合绑定到一个事件分派程序,每次插入新实例时都会发送消息

    
    function emit(newVal) {
        console.log(newVal);
    }
    
    const userList = [];
    
    const userListProxy = new Proxy(userList, {
        set(target, prop, val, receiver) {
            const result = Reflect.set(...arguments);
            // if (result) {
            //     emit(Reflect.get(target, prop, receiver));
            // }
            // 加个判断,对length的修改不发送消息
            if (prop !== 'length' && result) {
                emit(Reflect.get(target, prop, receiver));
            }
            return result;
        }
    });
    
    // push会对userList进行两次set操作,
    // 第一次新增一个元素,第二次修改length的值
    userListProxy.push('Wango');
    // Wango
    // 1
    userListProxy.push('Lily');
    // Lily
    // 2
    

    参考资料:

    《JavaScript高级程序设计(第4版)》

  • 相关阅读:
    vue中使用AES.js和crypto.js加密
    vue项目中使用日期获取今日,昨日,上周,下周,上个月,下个月的数据
    vue项目中的路由守卫
    vue中携带token以及发送ajax
    vue项目中的字符串每隔4位一个空格
    vue中Echarts的使用-自选效果
    平衡树——Treap
    2021牛客寒假算法训练营3题解(9/10)
    2021牛客寒假算法训练营1题解(9/10)
    模板、知识点积累
  • 原文地址:https://www.cnblogs.com/hycstar/p/14591158.html
Copyright © 2020-2023  润新知