Jinuss's blog Jinuss's blog
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

东流

Web、WebGIS技术博客
首页
  • 源码合集

    • Leaflet源码分析
    • Openlayers源码合集
    • vue3源码
  • HTML
  • CSS
  • 技术文档
  • GitHub技巧
  • 学习
  • 实用技巧
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • reactivity响应式

    • ref
    • reactive
    • 基础对象的代理
      • 概览
      • 源码分析
        • BaseReactiveHandler类
        • MutableReactiveHandler类
        • set
        • deleteProperty
        • has
        • ownKeys
        • ReadonlyReactiveHandler类
    • 数组代理的方法
    • 集合对象的代理
    • Reflect和Proxy详解
    • 依赖的收集与触发
    • effectScope解析
    • effect解析
    • reactive响应式依赖的收集与触发监听
    • 批量更新实现
    • ReactiveEffect类介绍
    • computed
  • 5.18源码学习》
  • reactivity响应式
东流
2025-08-13
目录

基础对象的代理

# 概览

基础对象的代理指的是对基础对象进行代理,使基础对象的属性可以被响应式地访问和修改。该实现具体参见 packages\reactivity\src\baseHandlers.ts

本文主要介绍如下四类基础对象的代理方法:

  • mutableHandlers:可读写代理
  • readonlyHandlers:只读代理
  • shallowReactiveHandlers:浅响应式代理
  • shallowReadonlyHandlers:浅只读代理

# 源码分析

实际上上述四类代理方法只是实例化了两个类MutableReactiveHandler和ReadonlyReactiveHandler

const mutableHandlers = /* @__PURE__ */ new MutableReactiveHandler();
const readonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler();
const shallowReactiveHandlers = /* @__PURE__ */ new MutableReactiveHandler(true);
const shallowReadonlyHandlers = /* @__PURE__ */ new ReadonlyReactiveHandler(true);
1
2
3
4

而MutableReactiveHandler和ReadonlyReactiveHandler都是继承于BaseReactiveHandler类的,BaseReactiveHandler类的主要功能是定义基础的代理方法,而MutableReactiveHandler和ReadonlyReactiveHandler类则是在基础的代理方法上进行了扩展,添加了可读写和只读的功能。

# BaseReactiveHandler类

BaseReactiveHandler类的实现如下:


function hasOwnProperty(key) {
  if (!isSymbol(key)) key = String(key);
  const obj = toRaw(this);
  // 依赖收集
  track(obj, "has", key);
  return obj.hasOwnProperty(key);
}

class BaseReactiveHandler {
  constructor(_isReadonly = false, _isShallow = false) {
    this._isReadonly = _isReadonly;
    this._isShallow = _isShallow;
  }
  get(target, key, receiver) {
    if (key === "__v_skip") return target["__v_skip"];
    const isReadonly2 = this._isReadonly, isShallow2 = this._isShallow;
    if (key === "__v_isReactive") {
      return !isReadonly2;
    } else if (key === "__v_isReadonly") {
      return isReadonly2;
    } else if (key === "__v_isShallow") {
      return isShallow2;
    } else if (key === "__v_raw") {
      if (receiver === (isReadonly2 ? isShallow2 ? shallowReadonlyMap : readonlyMap : isShallow2 ? shallowReactiveMap : reactiveMap).get(target) || // receiver is not the reactive proxy, but has the same prototype
      // this means the reciever is a user proxy of the reactive proxy
      Object.getPrototypeOf(target) === Object.getPrototypeOf(receiver)) {
        return target;
      }
      return;
    }
    const targetIsArray = isArray(target);
    if (!isReadonly2) {
      let fn;
      if (targetIsArray && (fn = arrayInstrumentations[key])) {
        return fn;
      }
      if (key === "hasOwnProperty") {
        return hasOwnProperty;
      }
    }
    const res = Reflect.get(target, key, isRef(target) ? target : receiver);
    if (isSymbol(key) ? builtInSymbols.has(key) : isNonTrackableKeys(key)) {
      return res;
    }
    if (!isReadonly2) {
      track(target, "get", key);
    }
    if (isShallow2) {
      return res;
    }
    if (isRef(res)) {
      return targetIsArray && isIntegerKey(key) ? res : res.value;
    }
    if (isObject(res)) {
      return isReadonly2 ? readonly(res) : reactive(res);
    }
    return res;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60

BaseReactiveHandler类只是定义了get()方法,当读取代理对象时,会触发get()方法进行拦截,在非只读的情况下,会调用track方法进行依赖收集。如下是BaseReactiveHandler类的实现过程分析:

  1. 类的构造器接收两个参数:_isReadonly 和 _isShallow,分别表示是否只读和是否是浅层响应式.
  2. get()方法接收三个参数:target目标对象、key属性名、receiver代理对象。当get()方法被触发时,若key是__v_isReactive、__v_isShallow或者__v_raw,则根据实例的_isReadonly或者_isShallow返回对应的布尔值.
  3. 若key是__v_raw,则根据_isReadonly和_isShallow确定代理对象的缓存(即调用createReactiveObject中的proxyMap缓存变量),然后比较receiver是否是缓存中的代理对象,如果是,则返回目标对象target;若不是,则判断target和receiver的原型是否相等,若相等,则返回目标对象target.如果二者皆不相等,则什么也不返回.
  4. 若key不是上述属性,则判断target是否是数组。如果是可写的,且target是数组,key又是数组的属性,那么就返回数组的方法。若key是hasOwnProperty,则返回自定义的hasOwnProperty方法,该方法的实现如上,该方法的作用是判断target是否有key属性,并且调用track进行依赖收集.
  5. 调用Reflect.get(target, key, receiver)方法获取target上key的值res.
  6. 判断key是不是内置的Symbol属性或一些普通属性__proto__,__v_isRef,__isVue,若是,则直接返回res,避免对这些属性进行依赖收集.
  7. 判断是否只读,若不是只读,则调用track进行依赖收集.
  8. 判断是否是浅层响应式,若是,则直接返回res,避免对res进行递归代理.
  9. 判断res是否是Ref对象,若是,则继续判断,若target是数组且key是整数索引,则返回res;否则返回res.value.
  10. 若res是对象,则判断是否只读,若不是只读,则递归调用reactive进行代理,否则递归调用readonly进行代理.
  11. 最后返回res.

# MutableReactiveHandler类

MutableReactiveHandler的实现如下:

class MutableReactiveHandler extends BaseReactiveHandler {
  constructor(isShallow2 = false) {
    super(false, isShallow2);
  }
  set(target, key, value, receiver) {
    let oldValue = target[key];
    if (!this._isShallow) {
      const isOldValueReadonly = isReadonly(oldValue);
      if (!isShallow(value) && !isReadonly(value)) {
        oldValue = toRaw(oldValue);
        value = toRaw(value);
      }
      if (!isArray(target) && isRef(oldValue) && !isRef(value)) {
        if (isOldValueReadonly) {
          return false;
        } else {
          oldValue.value = value;
          return true;
        }
      }
    }
    const hadKey = isArray(target) && isIntegerKey(key) ? Number(key) < target.length : hasOwn(target, key);
    const result = Reflect.set(target, key, value, receiver);
    if (target === toRaw(receiver)) {
      if (!hadKey) {
        trigger(target, "add", key, value);
      } else if (hasChanged(value, oldValue)) {
        trigger(target, "set", key, value, oldValue);
      }
    }
    return result;
  }
  deleteProperty(target, key) {
    const hadKey = hasOwn(target, key);
    const oldValue = target[key];
    const result = Reflect.deleteProperty(target, key);
    if (result && hadKey) {
      trigger(target, "delete", key, void 0, oldValue);
    }
    return result;
  }
  has(target, key) {
    const result = Reflect.has(target, key);
    if (!isSymbol(key) || !builtInSymbols.has(key)) {
      track(target, "has", key);
    }
    return result;
  }
  ownKeys(target) {
    track(
      target,
      "iterate",
      isArray(target) ? "length" : ITERATE_KEY
    );
    return Reflect.ownKeys(target);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

MutableReactiveHandler类继承于BaseReactiveHandler类,在其内部定义了set、deleteProperty、has、ownKeys方法四个方法。在它的构造函数中,接受一个参数isShallow2表示是否是浅层响应,默认为false,然后调用super,响应式对象肯定不是只读的,所以super第一个参数是false。如下分析MutableReactiveHandler的四个方法。

# set

当target目标对象上的值发生改变,或者说是对target进行写操作时,会调用set方法。

set方法接收四个参数:target目标对象、key属性名、value属性值、receiver代理对象。

  1. 首先获取target的旧值oldValue,判断是否是浅层代理,若不是,则继续判断新值,若新值是深层响应式,则分别调用toRaw获取新值和旧值的原始值;然后判断,若target是对象,且旧值是Ref对象而新值不是Ref对象,若旧值是只读的,则返回false;否则将旧值的value属性赋值为新值,返回true.
  2. 若target不是数组,且key是整数索引且key的长度小于target数组的长度,则说明是在更新target[key]的值;若target不是数组,则调用自定义方法hasOwn(实际就是Object.prototype.hasOwnProperty)判断target是否有key属性. hadKey用于表示是更新还是新增操作,true则更新/false则新增.
  3. 调用Reflect.set设置target的key为value,返回结果保存至变量result。
  4. 判断target和receiver的原始对象是否相等,只有相等才触发副作用。这个检查是为了避免在原型链上的属性设置时错误地触发副作用。然后判断hadKey,若hadKey为true,则说明是更新操作,会先调用hasChanged判断新旧值是否相等,若不等,则调用trigger触发更新副作用;若hadKey为false,则说明是新增操作,调用trigger触发新增副作用.
  5. 最后返回result

# deleteProperty

deleteProperty方法在删除target上的某属性时会被触发。

deleteProperty方法接收两个参数:target目标对象、key属性名。

  1. 调用hasOwn判断target是否有key属性,判断结果记为hadKey,获取旧值oldValue。
  2. 调用Reflect.deleteProperty删除target的key属性,返回结果保存至变量result。
  3. 判断result与hadKey都为true,则调用trigger触发删除副作用。
  4. 最后返回result

# has

has方法会拦截in操作符。如下是它的处理流程:

  1. 调用Reflect.has判断target是否有key属性,记为result
  2. 判断key是否是Symbol类型或者key是否是内置的Symbol,若不是,则调用track进行依赖收集.
  3. 最后返回属性检测的结果result

# ownKeys

ownKeys方法会拦截Object.keys、Object.getOwnPropertyNames、Object.getOwnPropertySymbols、for...in循环。如下是它的处理流程:

  1. 调用track进行依赖收集。若target是数组,则跟踪length属性的变化;若target不是数组,则跟踪Symbol(iterator)。这样当对对象的属性添加、删除或数组长度变化时,就会触发相关的副作用函数。
  2. 最后返回目标对象的所有自有属性键

# ReadonlyReactiveHandler类

ReadonlyReactiveHandler类就更简单了,因为通过该类实例化的处理器方法都是针对只读对象的,所以它的set、deleteProperty方法都直接返回true,并在warn中提示目标对象是只读的。

ReadonlyReactiveHandler的实现如下:

class ReadonlyReactiveHandler extends BaseReactiveHandler {
  constructor(isShallow2 = false) {
    super(true, isShallow2);
  }
  set(target, key) {
    {
      warn(
        `Set operation on key "${String(key)}" failed: target is readonly.`,
        target
      );
    }
    return true;
  }
  deleteProperty(target, key) {
    {
      warn(
        `Delete operation on key "${String(key)}" failed: target is readonly.`,
        target
      );
    }
    return true;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
编辑 (opens new window)
上次更新: 2025/08/15, 09:55:22
reactive
数组代理的方法

← reactive 数组代理的方法→

最近更新
01
computed
08-26
02
ReactiveEffect类介绍
08-26
03
批量更新实现
08-25
更多文章>
Theme by Vdoing | Copyright © 2024-2025 东流 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式