Proxy

  • Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程
  • Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。 Proxy %26 Reflect - 图1 ```javascript { // ES5 let obj = {}; let newVal = “”; Object.defineProperty(obj, “name”, { get() {
    1. return newVal;
    }, set(val) {
    1. newVal = val;
    }, }); obj.name = “wuchendi”; console.log(obj.name); // wuchendi }

{ let obj = { time: “2017-03-11”, name: “wcd”, r: 123, }; let monitor = new Proxy(obj, { // 拦截对象属性的读取 get(target, key) { return target[key].replace(“2017”, “2018”); }, // 拦截对象设置属性 set(target, key, value) { if (key === “name”) { return (target[key] = value); } else { return target[key]; } }, // 拦截key in object操作 has(target, key) { if (key === “name”) { return target[key]; } else { return false; } }, // 拦截delete deleteProperty(target, key) { if (key.indexOf(““) > -1) { delete target[key]; return true; } else { return target[key]; } }, // 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames ownKeys(target) { return Object.keys(target).filter((item) => item != “time”); }, });

  1. console.log("get", monitor.time); // get 2018-03-11
  2. monitor.time = "2018";
  3. monitor.name = "wuchendi";
  4. console.log("set", monitor.time, monitor); // set 2018-03-11 Proxy {time: "2017-03-11", name: "wuchendi", _r: 123}
  5. console.log("has", "name" in monitor, "time" in monitor); // has true false
  6. // delete monitor.time;
  7. // console.log('delete', monitor);
  8. // delete monitor._r;
  9. // console.log('delete', monitor);
  10. console.log("ownKeys", Object.keys(monitor)); // ownKeys ["name", "_r"]

}

{ // apply let sum = (…args) => { let num = 0; args.forEach((item) => { num += item; }); return num; };

  1. sum = new Proxy(sum, {
  2. apply(target, ctx, args) {
  3. return target(...args) * 2;
  4. },
  5. });
  6. console.log(sum(1, 2)); // 6
  7. console.log(sum.call(null, 1, 2, 3)); // 12
  8. console.log(sum.apply(null, [1, 2, 3])); // 12

}

{ //constructor new let User = class { constructor(name) { this.name = name; } };

  1. User = new Proxy(User, {
  2. construct(target, args, newTarget) {
  3. return new target(...args);
  4. },

}); console.log(new User(“wuchendi”)); // User { name: ‘wuchendi’ }  }

  1. <a name="xsYgP"></a>
  2. ## Reflect
  3. - Reflect 对象与 Proxy 对象一样,也是 ES6 为了操作对象而提供的新 API。 Reflect 对象的设计目的有这样几个。
  4. - 将 Object 对象的一些明显属于语言内部的方法(比如 Object.defineProperty),放到 Reflect 对象上。现阶段,某些方法同时在 Object 和 Reflect 对象上部署,未来的新方法将只部署在 Reflect 对象上
  5. - 修改某些 Object 方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)在无法定义属性时,会抛出一个错误,而 Reflect.defineProperty(obj, name, desc)则会返回 false
  6. - 让Object 操作变成函数行为
  7. - Reflect 对象的方法与 Proxy 对象的方法一一对应
  8. ```javascript
  9. {
  10. let obj = {
  11. time: "2017-03-11",
  12. name: "wcd",
  13. _r: 123,
  14. };
  15. console.log("Reflect get", Reflect.get(obj, "time")); // Reflect get 2017-03-11
  16. Reflect.set(obj, "name", "wuchendi");
  17. console.log(obj); // { time: '2017-03-11', name: 'wuchendi', _r: 123 }
  18. console.log("has", Reflect.has(obj, "name")); // has true
  19. }
  20. {
  21. function validator(target, validator) {
  22. return new Proxy(target, {
  23. _validator: validator,
  24. set(target, key, value, proxy) {
  25. if (target.hasOwnProperty(key)) {
  26. let va = this._validator[key];
  27. if (!!va(value)) {
  28. return Reflect.set(target, key, value, proxy);
  29. } else {
  30. throw Error(`不能设置${key}到${value}`);
  31. }
  32. } else {
  33. throw Error(`${key} 不存在`);
  34. }
  35. },
  36. });
  37. }
  38. const personValidators = {
  39. name(val) {
  40. return typeof val === "string";
  41. },
  42. age(val) {
  43. return typeof val === "number" && val > 18;
  44. },
  45. mobile(val) {},
  46. };
  47. class Person {
  48. constructor(name, age) {
  49. this.name = name;
  50. this.age = age;
  51. this.mobile = "189****0530";
  52. return validator(this, personValidators);
  53. }
  54. }
  55. const person = new Person("wuchendi", 22);
  56. console.info(person); // Person { name: 'wuchendi', age: 22, mobile: '189****0530' }
  57. person.name = "dd";
  58. console.info(person); // Person { name: 'dd', age: 22, mobile: '189****0530' }
  59. }