ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

js的Proxy和Reflect的应用场景

2022-01-18 14:02:37  阅读:125  来源: 互联网

标签:return target console js Reflect Proxy new const log


proxy基本使用方式

/**
 * target: 表示要代理的目标,可以是object, array, function类型
 * handler: 是一个对象,可以编写各种代理的方法
 */
const proxy = new Proxy(target, handler);

1. 跟踪属性访问

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

2. 隐藏属性

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);
}

3. 属性验证

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!

4. 函数和构造函数参数验证

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

5. 数据绑定和可观察对象

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

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

6. 代理数组

const arr = [1, 2, 3, 4];
const arrProxy = new Proxy(arr, {
  get(target, key, receiver) {
    console.log('arrProxy.get', target, key);
    return Reflect.get(target, key, receiver);
  },
  set(target, key, value, receiver) {
    console.log('arrProxy.set', target, key, value);
    return Reflect.set(target, key, value, receiver);
  },
  deleteProperty(target, key) {
    console.log('arrProxy.deleteProperty', target, key);
    return Reflect.deleteProperty(target, key);
  },
});

7. 统计函数被调用的上下文和次数

const countExecute = (fn) => {
  let count = 0;
 
  return new Proxy(fn, {
    apply(target, ctx, args) {
      ++count;
      console.log('ctx上下文:', ctx);
      console.log(`${fn.name} 已被调用 ${count} 次`);
      return Reflect.apply(target, ctx, args);
    },
  });
};

const getSum = (...args) => {
  if (!args.every((item) => typeof item === 'number')) {
    throw new TypeError('参数应当均为number类型');
  }
  return args.reduce((sum, item) => sum + item, 0);
};
 
const useSum = countExecute(getSum);
 
useSum(1, 2, 3); // getSum 已被调用 1 次
 
useSum.apply(window, [2, 3, 4]); // getSum 已被调用 2 次
 
useSum.call(person, 3, 4, 5); // getSum 已被调用 3 次

8. 实现一个防抖功能

const throttleByProxy = (fn, rate) => {
  let lastTime = 0;
  return new Proxy(fn, {
    apply(target, ctx, args) {
      const now = Date.now();
      if (now - lastTime > rate) {
        lastTime = now;
        return Reflect.apply(target, ctx, args);
      }
    },
  });
};
 
const logTimeStamp = () => console.log(Date.now());
window.addEventListener('scroll', throttleByProxy(logTimeStamp, 300));

9. 实现观察者模式

我们在这里实现一个最简单类 mobx 观察者模式。

const list = new Set();
const observe = (fn) => list.add(fn);
const observable = (obj) => {
  return new Proxy(obj, {
    set(target, key, value, receiver) {
      const result = Reflect.set(target, key, value, receiver);
      list.forEach((observer) => observer());
      return result;
    },
  });
};
const person = observable({ name: 'wenzi', age: 20 });
const App = () => {
  console.log(`App -> name: ${person.name}, age: ${person.age}`);
};
observe(App);

person就是使用 Proxy 创建出来的代理对象,每当 person 中的属性发生变化时,就会执行 App()函数。这样就实现了一个简单的响应式状态管理。

 

出处:https://www.cnblogs.com/hycstar/p/14591158.html?ivk_sa=1024320u

        https://zxbcw.cn/post/212296/

标签:return,target,console,js,Reflect,Proxy,new,const,log
来源: https://www.cnblogs.com/mengff/p/15817513.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有