Proxy、Reflect和WeakMap

Proxy、Reflect和WeakMap是ES6中引入的三个新的JavaScript特性。

Proxy

Proxy对象用于定义基本操作的自定义行为(例如属性查找、赋值、枚举、函数调用等)。

const handler = {
  get(target, prop, receiver) {
    console.log(`GET ${prop}`);
    return Reflect.get(target, prop, receiver);
  },
  set(target, prop, value, receiver) {
    console.log(`SET ${prop} = ${value}`);
    return Reflect.set(target, prop, value, receiver);
  }
};
const target = { foo: 'bar' };
const proxy = new Proxy(target, handler);
proxy.foo; // 控制台输出: GET foo
proxy.foo = 'baz'; // 控制台输出: SET foo = baz

在上面的例子中,handler对象定义了getset陷阱,这些陷阱会在对应的操作发生时被调用。Proxy对象proxy拦截了对target对象的属性访问和赋值操作,并打印出相应的信息。

Reflect

Reflect是一个内置的对象,它提供拦截JavaScript操作的方法。这些方法与Proxy对象的陷阱方法相同。Reflect不是一个函数对象,因此它是不可构造的。

const obj = {
  foo: 1,
  bar: 2,
  get baz() {
    return this.foo + this.bar;
  }
};
console.log(Reflect.get(obj, 'foo')); // 1
console.log(Reflect.set(obj, 'foo', 3)); // true
console.log(obj.foo); // 3

在上面的例子中,Reflect.get()Reflect.set()被用来获取和设置obj对象的属性。

WeakMap

WeakMap是一种特殊的Map,只接受对象作为键名(null除外),并且键名所指向的对象不计入垃圾回收机制。

const weakMap = new WeakMap();
const obj1 = {};
const obj2 = {};
weakMap.set(obj1, 'hello');
weakMap.set(obj2, 'world');
console.log(weakMap.get(obj1)); // 'hello'
console.log(weakMap.get(obj2)); // 'world'
// 当obj1和obj2被清除后,weakMap中的条目也会自动被清除
obj1 = null;
obj2 = null;

在上面的例子中,weakMap是一个WeakMap实例,它使用了obj1obj2作为键名。当obj1obj2被设置为null后,它们可以被垃圾回收器回收,weakMap中对应的条目也会被自动清除。
这三个特性结合起来,可以用于实现私有变量、函数柯里化、数据绑定等高级功能。例如,结合ProxyWeakMap可以实现一个简单的私有属性存储方案:

const privateData = new WeakMap();
class Person {
  constructor(name, age) {
    privateData.set(this, { name, age });
  }
  get name() {
    return privateData.get(this).name;
  }
  get age() {
    return privateData.get(this).age;
  }
}
const person = new Person('Alice', 25);
console.log(person.name); // 'Alice'
console.log(person.age); // 25

在这个例子中,privateData是一个WeakMap,用于存储每个Person实例的私有数据。由于WeakMap的键名是弱引用,所以当Person实例被垃圾回收时,对应的私有数据也会被自动清除。