Vue3 的响应式系统源码级 shallowReactive 与 shallowReadonly 的实现原理与区别
字数 1288 2025-11-27 08:24:19

Vue3 的响应式系统源码级 shallowReactive 与 shallowReadonly 的实现原理与区别

1. 知识描述
shallowReactiveshallowReadonly 是 Vue3 响应式系统中用于控制响应式深度的 API。它们的核心区别在于:

  • shallowReactive 只对对象的第一层属性进行响应式处理,深层属性保持原始状态。
  • shallowReadonly 只对对象的第一层属性进行只读代理,深层属性可被修改但不会触发响应。
    理解其实现需结合 Vue3 的 Proxy 代理机制和递归响应式转换逻辑。

2. 实现原理分析
(1)shallowReactive 的源码级实现

  • 创建代理:与 reactive 类似,使用 Proxy 拦截对象的读写操作,但关键区别在于 get 拦截器不会递归调用 reactive
  • get 拦截器逻辑
    const shallowGet = (target, key, receiver) => {  
      // 依赖收集(与 reactive 相同)  
      track(target, key);  
      const res = Reflect.get(target, key, receiver);  
      // 关键:直接返回原始值,不进行深层响应式转换  
      return res;  
    };  
    
  • set 拦截器逻辑
    const shallowSet = (target, key, value, receiver) => {  
      const oldValue = target[key];  
      // 触发更新(仅针对第一层属性)  
      const result = Reflect.set(target, key, value, receiver);  
      if (hasChanged(value, oldValue)) {  
        trigger(target, key);  
      }  
      return result;  
    };  
    
  • 深层属性处理:若访问 obj.nested(嵌套对象),返回的是原始对象而非响应式代理,修改 obj.nested.x 不会触发响应。

(2)shallowReadonly 的源码级实现

  • 只读代理的拦截逻辑
    const shallowReadonlyHandlers = {  
      get: (target, key, receiver) => {  
        // 第一层属性只读,但不收集依赖(因为不会触发更新)  
        const res = Reflect.get(target, key, receiver);  
        return res;  
      },  
      set: (target, key, value) => {  
        // 第一层属性禁止修改(开发环境会报警告)  
        console.warn(`Set operation on key "${key}" failed: target is readonly.`);  
        return true;  
      }  
    };  
    
  • 深层属性特性:若修改 obj.nested.x,由于 obj.nested 是原始对象,修改不会触发警告或响应,但直接修改 obj.nested(如 obj.nested = {})会被 set 拦截器阻止。

3. 与 reactive/readonly 的对比

API 第一层属性 深层属性
reactive 响应式 递归响应式
shallowReactive 响应式 原始对象(无响应)
readonly 只读 递归只读
shallowReadonly 只读 原始对象(可修改但无响应)

4. 设计动机与使用场景

  • 性能优化:避免深层递归代理大型对象(如配置信息)。
  • 可控响应式粒度:明确指定哪些层级需要响应式(如组件 props 的浅层只读特性)。
  • markRaw 协同:若深层属性需完全避免响应式,可结合 markRaw 标记。

5. 总结
shallowReactiveshallowReadonly 通过简化 Proxy 拦截器的递归逻辑,实现了响应式粒度的精细控制。其核心区别在于深层属性的处理策略,前者保持原始值可修改但无响应,后者则完全禁止第一层修改而放任深层操作。

Vue3 的响应式系统源码级 shallowReactive 与 shallowReadonly 的实现原理与区别 1. 知识描述 shallowReactive 和 shallowReadonly 是 Vue3 响应式系统中用于控制响应式深度的 API。它们的核心区别在于: shallowReactive 只对对象的第一层属性进行响应式处理,深层属性保持原始状态。 shallowReadonly 只对对象的第一层属性进行只读代理,深层属性可被修改但不会触发响应。 理解其实现需结合 Vue3 的 Proxy 代理机制和递归响应式转换逻辑。 2. 实现原理分析 (1)shallowReactive 的源码级实现 创建代理 :与 reactive 类似,使用 Proxy 拦截对象的读写操作,但关键区别在于 get 拦截器不会递归调用 reactive 。 get 拦截器逻辑 : set 拦截器逻辑 : 深层属性处理 :若访问 obj.nested (嵌套对象),返回的是原始对象而非响应式代理,修改 obj.nested.x 不会触发响应。 (2)shallowReadonly 的源码级实现 只读代理的拦截逻辑 : 深层属性特性 :若修改 obj.nested.x ,由于 obj.nested 是原始对象,修改不会触发警告或响应,但直接修改 obj.nested (如 obj.nested = {} )会被 set 拦截器阻止。 3. 与 reactive/readonly 的对比 | API | 第一层属性 | 深层属性 | |------------------|---------------|---------------------------| | reactive | 响应式 | 递归响应式 | | shallowReactive | 响应式 | 原始对象(无响应) | | readonly | 只读 | 递归只读 | | shallowReadonly | 只读 | 原始对象(可修改但无响应) | 4. 设计动机与使用场景 性能优化 :避免深层递归代理大型对象(如配置信息)。 可控响应式粒度 :明确指定哪些层级需要响应式(如组件 props 的浅层只读特性)。 与 markRaw 协同 :若深层属性需完全避免响应式,可结合 markRaw 标记。 5. 总结 shallowReactive 和 shallowReadonly 通过简化 Proxy 拦截器的递归逻辑,实现了响应式粒度的精细控制。其核心区别在于深层属性的处理策略,前者保持原始值可修改但无响应,后者则完全禁止第一层修改而放任深层操作。