一、Javascript Proxy 代理

JavaScript 的 Proxy 对象允许你创建一个代理,用于拦截和自定义对对象的基本操作(例如属性查找、赋值、枚举、函数调用等)。这使得 Proxy 在处理对象时具有非常强大的功能,比如数据验证、观察和操作等。

创建和使用 Proxy

下面是一个基本的 Proxy 使用示例:

1const target = {
2  message: 'Hello, world!'
3}
4
5const handler = {
6  get(target, prop, receiver) {
7    console.log(`Getting the property ${prop}`)
8    return Reflect.get(...arguments)
9  },
10  set(target, prop, value, receiver) {
11    console.log(`Setting the property ${prop} with value ${value}`)
12    return Reflect.set(...arguments)
13  }
14}
15
16const proxy = new Proxy(target, handler)
17
18console.log(proxy.message)  // Getting the property message \n Hello, world!
19
20proxy.message = 'Hello, Proxy!'  // Setting the property message with value Hello, Proxy!

 

常用的陷阱方法

这些陷阱方法可以组合使用,来实现各种复杂的代理行为:

  • get(target, prop, receiver): 访问属性时调用
  • set(target, prop, value, receiver): 设置属性值时调用
  • has(target, prop): 使用 in 操作符检查属性是否存在时调用
  • deleteProperty(target, prop): 删除属性时调用
  • ownKeys(target): 使用 Object.keys() 或类似方法时调用,返回对象的所有属性名
  • apply(target, thisArg, args): 调用函数时调用
  • construct(target, args): 使用 new 关键字创建实例时调用

 

二、Vue Reactive 响应式原理

查看 Vue 3.4 源码对 Reactive (packages/reactivity/src/reactive.ts) 的实现,核心是使用 Javascript Proxy 代理: 

1export function reactive<T extends object>(target: T): Reactive<T>
2export function reactive(target: object) {
3  // if trying to observe a readonly proxy, return the readonly version.
4  if (isReadonly(target)) {
5    return target
6  }
7  return createReactiveObject(
8    target,
9    false,
10    mutableHandlers,
11    mutableCollectionHandlers,
12    reactiveMap,
13  )
14}

 

createReactiveObject 函数方法如下 (下面只显示核心部分):

Javascript Proxy 代理对象接收两个参数 target、handler,Vue Reactive 在 handler 中主要实现了 get 和 set 方法对属性进行依赖追踪和触发更新,当然也实现了其他方法,例如 has、deleteProperty、ownKeys

1function createReactiveObject(
2  target: Target,
3  isReadonly: boolean,
4  baseHandlers: ProxyHandler<any>,
5  collectionHandlers: ProxyHandler<any>,
6  proxyMap: WeakMap<Target, any>,
7) {
8  /// ...
9  const proxy = new Proxy(
10    target,
11    targetType === TargetType.COLLECTION ? collectionHandlers : baseHandlers,
12  )
13  /// ...
14  return proxy
15}

 

三、其他

学习的记录,仅供参考