Skip to content

Proxy

一个 Proxy 对象包装另一个对象并拦截诸如读取/写入属性和其他操作,可以选择自行处理它们,或者透明地允许该对象处理它们。

参数详解

  • target

    目标对象。

  • property

    被获取的属性名。

  • receiver

    Proxy 或者继承 Proxy 的对象

    TIP

    继承 Proxy 对象举例:

    js
    let foo = { name: "foo" };
    let proxyFoo = new Proxy(foo, {});
    let bar = Object.create(proxyFoo);

代理过程

  • eg1
js
let bar = "bar";
let foo = {
  get name() {
    console.log("call obj name.");
    return bar;
  },
  set name(val) {
    bar = val;
  },
};
let proxyFoo = new Proxy(foo, {
  get: function(target, property, receiver) {
    console.log("call proxy1 name.");
    return Reflect.get(target, property, receiver);
  },
});
let voo = new Proxy(proxyFoo, {
  get: function(target, property, receiver) {
    console.log("call proxy2 name.");
    return Reflect.get(target, property, receiver);
  },
});
console.log(voo.name);
// call proxy2 name.
// call proxy1 name.
// call obj name.
// bar
  • eg2
js
let foo = {
  bar: "bar",
  get name() {
    console.log("call obj name.");
    return this.bar;
  },
  set name(val) {
    this.bar = val;
  },
};
let proxyFoo = new Proxy(foo, {
  get: function(target, property, receiver) {
    console.log("call proxy1 name.");
    return Reflect.get(target, property, receiver);
  },
});
let voo = new Proxy(proxyFoo, {
  get: function(target, property, receiver) {
    console.log("call proxy2 name.");
    return Reflect.get(target, property, receiver); // receiver 换为proxyFoo 或者 foo
  },
});
console.log(voo.name);

改变 20 行参数后结果

receiver

call proxy2 name.
call proxy1 name.
call obj name.
call proxy2 name.
call proxy1 name.
bar

proxyFoo

call proxy2 name.
call proxy1 name.
call obj name.
call proxy1 name.
bar

foo

call proxy2 name.
call proxy1 name.
call obj name.
bar

Reflect

Reflect.get()方法与从 对象 (target[propertyKey]) 中读取属性类似,但它是通过一个函数执行来操作的。

  • 语法:Reflect.get(target, propertyKey[, receiver])
  • 参数:
parammeaning
target需要取值的目标对象
propertyKey需要获取的值的键值
receiver如果target对象中指定了getterreceiver则为getter调用时的this值。会改变this指向

Map、Set、WeakSet、WeakMap 的监听

js
let map = new Map([["name", "zhengcaiyun"]]);
let mapProxy = new Proxy(map, {
  get(target, key, receiver) {
    console.log("取值:", key);
    return Reflect.get(target, key, receiver);
  },
});
mapProxy.get("name");

Uncaught TypeError: Method Map.prototype.get called on incompatible receiver [object Object]

Map、Set 对象赋值、取值和他们内部的 this 指向有关系,但这里的 this 指向的是其实是 Proxy 对象,所以得这样干

js
let map = new Map([["name", "wangyangyang"]]);
let mapProxy = new Proxy(map, {
  get(target, key, receiver) {
    var value = Reflect.get(...arguments);
    console.log("取值:", ...arguments);
    return typeof value == "function" ? value.bind(target) : value;
  },
});
mapProxy.get("name");
js
let foo = new Map();
foo.set(1, 2);
let bar = new Proxy(foo, {
  get() {
    return Reflect.get(...arguments);
  },
});

bar.get; //  foo实例的get方法

bar.get(1); // foo实例的get方法在bar对象上调用,相当于get方法里的this指向了bar

console.log(bar.get.call(foo, 1)); //重新给指向this

原文