me

Proxy


Proxy

  • Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义 (如属性查找,赋值,枚举,函数调用等)
  • 目标对象既可以直接被操作,也可以通过代理来操作,但直接操作会绕过代理实施的行为
  • proxy 在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截
const p = new Proxy(target, handler);

traps(捕获器)

提供属性访问的方法:每个捕获器都对应一种基本操作,可以直接或者间接在代理对象上使用

每次代理对象上调用这些基本操作是,代理可以在这些操作传播到目标对象之前先调用捕获器函数,从而拦截并修改相应的行为

const target = {
  name: "zhangsan",
};
const handler = {
  get(target, key) {
    console.log(`${key} 被读取`);
    return target[key];
  },
  set(target, key, value) {
    console.log(`${key} 被设置为 ${value}`);
    target[key] = value;
  },
};
const proxy = new Proxy(target, handler);
proxy.name;
//name 被读取
proxy.name = "lisi";
//name 被设置为 lisi
console.log(target.name);
//lisi

Proxy.revocable()

Proxy.revocable()方法可以用来创建一个可撤销的代理对象

const revocable = Proxy.revocable({}, {
  get(target, name) {
    return "[[" + name + "]]";
  },
});
const proxy = revocable.proxy;
proxy.foo; // "[[foo]]"
revocable.revoke();
console.log(proxy.foo); // 抛出 TypeError

handler 的代理范围

handler.has()

返回一个布尔值

const handler1 = {
  has(target, key) {
    if (key[0] === "_") {
      return false;
    }
    return key in target;
  },
};
const monster1 = {
  _secret: "easily scared",
  eyeCount: 4,
};
const proxy1 = new Proxy(monster1, handler1);
console.log("eyeCount" in proxy1); // true
console.log("_secret" in proxy1); // false
console.log("_secret" in monster1); //true

handler.get()

可以返回任意值

const p = new Proxy(target, {
  get(target, property, receiver) {
    return ...
  }
})

handler.set()

默认返回 true

handler.getPrototypeOf()

返回值必须是一个对象或者 null

const obj = {};
const proto = {};
const handler = {
  getPrototypeOf(target) {
    console.log(target === obj); // true
    console.log(this === handler); // true
    return proto;
  },
};

const p = new Proxy(obj, handler);
console.log(Object.getPrototypeOf(p) === proto);

handler.setPrototypeOf()

成功修改了[[Prototype]],setPrototypeOf方法返回 true,否则返回 false 或者抛出异常

handler.isExtensible()

必须返回一个 Boolean 值或可转换成 Boolean 的值

const p = new Proxy({}, {
  isExtensible(target) {
    console.log("called");
    return true; //也可以 return 1;等表示为 true 的值
  },
});

console.log(Object.isExtensible(p));

handler.preventExtensions()

返回一个布尔值

const p = new Proxy({}, {
  preventExtensions(target) {
    console.log("called");
    Object.preventExtensions(target);
    return true;
  },
});

console.log(Object.preventExtensions(p));

handler.getOwnPropertyDescriptor()

必须返回一个对象或 undefined

const p = new Proxy({ a: 20 }, {
  getOwnPropertyDescriptor(target, prop) {
    console.log("called: " + prop);
    return { configurable: true, enumerable: true, value: 10 };
  },
});

console.log(Object.getOwnPropertyDescriptor(p, "a").value);
// "called: a"
//10

handler.defineProperty()

必须以一个 Boolean 返回,表示定义该属性的操作成功与否

const p = new Proxy({}, {
  defineProperty: function (target, prop, descriptor) {
    console.log("called: " + prop);
    return true;
  },
});

const desc = { configurable: true, enumerable: true, value: 10 };
Object.defineProperty(p, "a", desc); // "called: a"

handler.deleteProperty()

必须返回一个 Boolean 类型的值,表示该属性是否被成功删除

const p = new Proxy({}, {
  deleteProperty: function (target, prop) {
    console.log("called: " + prop);
    return true;
  },
});
delete p.a;

handler.ownKeys()

ownKeys 方法必须返回一个可枚举对象

const p = new Proxy({}, {
  ownKeys: function (target) {
    return ["a", "b", "c"];
  },
});
console.log(Object.getOwnPropertyNames(p));
// [ 'a', 'b', 'c' ]

handler.apply()

可以返回任何值

const p = new Proxy(target, {
  apply(target, thisArg, argumentsList) {
  },
});

handler.construct()

construct 方法必须返回一个对象

const p = new Proxy(target, {
  construct(target, argumentsList, newTarget) {
    return {};
  },
});