ES6-proxy

136 阅读2分钟

Proxy 是 ES6 引入的一个新特性,它允许你定义一个对象的行为,拦截对对象的操作,比如读取属性、设置属性、删除属性、函数调用等。

let proxy = new Proxy(target, handler);
  • target 是目标对象,即你希望操作的对象。
  • handler 是一个对象,其中定义了各种拦截操作,比如 getsetdeleteProperty 等。
  • 示例:
const proxy = new Proxy(target, {  
  get(target, prop) { return Reflect.get(target, prop); }  
});  

基本方法

1 捕获对象的读取操作(get)

通过 get 方法,你可以拦截对对象属性的读取。

const target = {
  message: 'Hello, world!',
};

const handler = {
  get(target, prop) {
    if (prop in target) {
      return `Intercepted: ${target[prop]}`;
    } else {
      return `Property ${prop} does not exist`;
    }
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.message); // 输出: Intercepted: Hello, world!
console.log(proxy.nonExistent); // 输出: Property nonExistent does not exist
  • 当你读取 proxy.message 时,get 捕获了这个操作,并返回自定义的结果。
  • 如果属性不存在,get 可以自定义返回值。

2 捕获对象的设置操作(set)

通过 set 方法,你可以拦截对对象属性的赋值操作。

const target = {};

const handler = {
  set(target, prop, value) {
    console.log(`Setting ${prop} to ${value}`);
    target[prop] = value; // 默认将值设置到目标对象
    return true; // 表示操作成功
  }
};

const proxy = new Proxy(target, handler);

proxy.name = 'Alice'; // 输出: Setting name to Alice
console.log(target.name); // 输出: Alice
  • 在这里,每次你向 proxy 对象设置属性时,都会触发 set 方法,输出日志。

3 捕获对象的删除操作(deleteProperty)

deleteProperty 方法允许你拦截对对象属性的删除操作。

const target = {
  name: 'Alice'
};

const handler = {
  deleteProperty(target, prop) {
    if (prop === 'name') {
      console.log('Cannot delete name property');
      return false; // 阻止删除
    }
    delete target[prop];
    return true; // 允许删除
  }
};

const proxy = new Proxy(target, handler);

delete proxy.name; // 输出: Cannot delete name property
delete proxy.age; // 删除成功
console.log(target); // 输出: { name: 'Alice' }
  • 如果试图删除 name 属性,deleteProperty 方法阻止了这个操作,并输出一条消息。

4 捕获函数调用(apply)

Proxy 也可以用来拦截函数调用,控制函数的行为。

const target = function(message) {
  return `Hello, ${message}`;
};

const handler = {
  apply(target, thisArg, argumentsList) {
    console.log(`Called with arguments: ${argumentsList}`);
    return target.apply(thisArg, argumentsList); // 调用原始函数
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy('World')); // 输出: Called with arguments: World
                             // 输出: Hello, World
  • 每次调用 proxy 时,都会先触发 apply 方法,在这里你可以做一些操作(如日志记录),然后再调用原始的函数。

拦截方法

  • get(target, prop):拦截对属性的读取操作。

  • set(target, prop, value):拦截对属性的赋值操作。

  • has(target, prop):拦截 in 操作符。

  • deleteProperty(target, prop):拦截 delete 操作符。

  • apply(target, thisArg, argumentsList):拦截函数调用。

  • construct(target, args):拦截 new 操作符。

  • ownKeys(target):拦截对象的键操作(如 Object.keys()for...in)。

  • getOwnPropertyDescriptor(target, prop):拦截 Object.getOwnPropertyDescriptor() 操作。

Object.defineProperty (Vue2 中的做法)对比

Proxy 支持更全面的拦截,适用于复杂场景(如数据绑定、日志记录);defineProperty 仅限属性操作。