当前位置: 首页 > news >正文

vue3中的ref和reactive

第一节:ref和reactive的区别

在 Vue3 中,refreactive 是两种创建响应式数据的核心 API,它们的主要区别体现在数据结构响应式原理使用方式上。以下是详细对比:

1. 数据结构与响应式原理

ref
  • 本质:创建一个包装对象RefImpl),通过 .value 访问内部值。
  • 适用场景:基本类型(如 numberstring)、单个值的响应式处理。
  • 响应式原理:通过 Object.defineProperty().value 转换为 getter/setter。
const count = ref(0);
console.log(count.value); // 0
count.value = 1; // 修改值时触发响应式更新
reactive
  • 本质:创建一个深层响应式对象,对对象的所有嵌套属性都进行代理。
  • 适用场景:复杂对象、数组等引用类型的响应式处理。
  • 响应式原理:基于 ES6 Proxy 实现,拦截对象的属性访问和修改。
const state = reactive({count: 0,user: { name: 'Alice' }
});
console.log(state.count); // 无需 .value
state.count = 1; // 直接修改属性触发响应式更新

2. 语法与使用方式

ref
  • 声明:使用 ref(初始值),类型通过泛型指定。
  • 模板引用:在模板中自动解包,无需 .value
  • 组件中使用
    <script setup lang="ts">
    const count = ref<number>(0);
    const increment = () => {count.value++; // 必须使用 .value 修改值
    };
    </script><template><button @click="increment">{{ count }}</button> <!-- 模板中无需 .value -->
    </template>
    
reactive
  • 声明:使用 reactive(对象字面量),类型可通过接口或类型注解明确。
  • 模板引用:直接访问属性,无需 .value
  • 组件中使用
<script setup lang="ts">interface State {count: number;message: string;}const state = reactive<State>({count: 0,message: 'Hello'});const increment = () => {state.count++; // 直接修改属性};</script><template><button @click="increment">{{ state.count }}</button></template>
### 3. **类型系统差异**
#### `ref`
- 类型为 `Ref<T>`,访问值时需通过 `.value`,类型推导依赖泛型:```typescriptconst count = ref(0); // Ref<number>const message = ref<string>('hello'); // 显式指定类型
reactive
  • 类型为原始对象的代理类型,保留对象结构:
    const state = reactive({ count: 0 }); // 类型为 { count: number }
    
  • 注意:reactive 无法直接处理基本类型,必须包装在对象中:
    // 错误:无法直接让基本类型响应式
    const num = reactive(1); // 报错// 正确:包装在对象中
    const state = reactive({ num: 1 });
    

4. 解构与响应式丢失

ref
  • 通过 .value 保持响应式:
    const count = ref(0);
    const { value } = count; // value 不是响应式的
    
reactive
  • 直接解构会导致响应式丢失,需使用 toRefs
    const state = reactive({ count: 0 });
    const { count } = state; // count 不是响应式的// 使用 toRefs 保持响应式
    const { count } = toRefs(state); // count 是 Ref<number>
    

5. 适用场景对比

场景refreactive
基本类型响应式const count = ref(0)❌ 需包装在对象中
对象/数组响应式const obj = ref({})const obj = reactive({})
避免响应式丢失✅ 直接传递 .value❌ 需使用 toRefs 解构
函数参数传递✅ 可直接传递 Ref 实例❌ 需确保整个对象被代理
与第三方库集成✅ 可通过 .value 暴露原始值❌ Proxy 对象可能导致兼容性问题

6. 选择建议

  • 使用 ref 场景

    • 管理基本类型(如数字、字符串)。
    • 在组合式函数中返回单个响应式值。
    • 需要与 TypeScript 泛型紧密配合时(如表单验证)。
  • 使用 reactive 场景

    • 管理复杂对象或数组。
    • 避免过多 .value 语法,使代码更简洁。
    • 需要深层响应式监听时(如嵌套对象的变化)。

总结

特性refreactive
响应式原理Getter/Setter (Object.defineProperty)Proxy
数据类型任意类型(包装为 Ref 对象)仅对象/数组(需为引用类型)
访问方式模板中自动解包,JS 中需 .value直接访问属性
类型系统Ref<T>原始对象类型的代理
解构响应式保持响应式(.value需使用 toRefs 保持响应式

在实际开发中,两者通常结合使用:用 reactive 管理复杂状态对象,用 ref 处理简单值或作为函数返回值。

第二节:使用原生的javascript实现ref功能

下面我将使用原生JavaScript实现一个类似Vue3中ref的功能。ref的核心是创建一个响应式对象,通过.value属性访问和修改值,并在值变化时触发依赖更新。

实现思路

  1. 使用ES6的Proxy来拦截对象属性的访问和修改
  2. 创建一个包含value属性的对象,并对其进行代理
  3. 实现依赖收集和触发更新的机制
  4. 添加类型定义以支持TypeScript

原生JavaScript实现

// ref 实现
function ref(initialValue) {// 创建一个包含value属性的对象const refObject = {_value: initialValue,get value() {// 收集依赖track(refObject, 'value');return this._value;},set value(newValue) {this._value = newValue;// 触发更新trigger(refObject, 'value');}};// 返回一个Proxy,使其更加灵活return new Proxy(refObject, {get(target, key) {return target[key];},set(target, key, value) {target[key] = value;if (key === 'value') {trigger(target, key);}return true;}});
}// 存储依赖关系的WeakMap
// targetMap: WeakMap<target, depsMap>
// depsMap: Map<key, Set<effect>>
const targetMap = new WeakMap();// 收集依赖
function track(target, key) {if (!activeEffect) return;// 获取目标对象的依赖映射let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}// 获取属性的依赖集合let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = new Set()));}// 将当前活跃的副作用添加到依赖集合中dep.add(activeEffect);// 同时将依赖集合添加到副作用的依赖列表中activeEffect.deps.push(dep);
}// 触发更新
function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;// 创建要执行的副作用集合的副本const effects = new Set();const computedRunners = new Set();// 添加属性的依赖副作用if (depsMap.has(key)) {depsMap.get(key).forEach(effect => {if (effect.computed) {computedRunners.add(effect);} else {effects.add(effect);}});}// 先执行计算属性副作用computedRunners.forEach(computed => computed());// 再执行普通副作用effects.forEach(effect => effect());
}// 当前活跃的副作用
let activeEffect = null;// 创建副作用函数
function effect(fn, options = {}) {const effectFn = () => {try {activeEffect = effectFn;// 清除之前的依赖cleanup(effectFn);// 执行副作用函数并获取返回值return fn();} finally {activeEffect = null;}};// 存储该副作用的依赖集合列表effectFn.deps = [];// 标记是否为计算属性effectFn.computed = options.computed || false;// 如果不是计算属性,则立即执行if (!options.lazy) {effectFn();}return effectFn;
}// 清除副作用的依赖
function cleanup(effectFn) {effectFn.deps.forEach(dep => {dep.delete(effectFn);});effectFn.deps.length = 0;
}// 实现计算属性
function computed(getter) {let value;let dirty = true;// 创建一个计算属性的副作用const runner = effect(getter, {lazy: true,computed: true});return {get value() {if (dirty) {value = runner();dirty = false;}// 收集依赖,以便在依赖变化时重新计算track(this, 'value');return value;},set value(newValue) {console.warn('Computed value is readonly');}};
}// 示例用法
const count = ref(0);// 创建一个计算属性
const doubleCount = computed(() => count.value * 2);// 创建副作用监听count变化
effect(() => {console.log('Count changed:', count.value);
});// 修改count值
count.value = 1; // 输出: Count changed: 1
count.value = 2; // 输出: Count changed: 2// 访问计算属性
console.log(doubleCount.value); // 输出: 4

代码解释

  1. ref函数:创建一个包含value属性的对象,并使用Proxy代理它。当访问或修改value时,会触发tracktrigger函数。

  2. 依赖收集系统:使用WeakMap存储对象及其依赖关系,当读取响应式对象的属性时收集依赖,当修改属性时触发更新。

  3. 副作用函数effect函数创建一个响应式副作用,当依赖的响应式数据变化时会重新执行。

  4. 计算属性computed函数基于effect实现,具有缓存机制,只有在依赖变化时才会重新计算。

这个实现模拟了Vue3中ref的核心功能,包括响应式追踪、依赖收集和计算属性。在实际应用中,Vue3的实现更加复杂和健壮,还包括生命周期集成、错误处理和性能优化等方面的考虑。

原生 JavaScript 实现的 ref 功能与 Vue3 中的 ref 有哪些区别?

原生 JavaScript 实现的 ref 功能与 Vue3 中的 ref 在核心原理上相似,但在实现细节、功能完整性和性能优化方面存在显著差异。以下是主要区别:

1. 底层实现差异

原生实现
  • 依赖收集:使用 WeakMap + Map + Set 手动管理依赖关系。
  • 响应式触发:通过 Object.definePropertyProxy 拦截属性访问。
  • 示例
    const refObject = {_value: initialValue,get value() {track(this, 'value');return this._value;},set value(newValue) {this._value = newValue;trigger(this, 'value');}
    };
    
Vue3 实现
  • 依赖收集:基于 ReactiveEffect 类和全局副作用栈,支持嵌套副作用。
  • 响应式触发:通过 Proxy 实现深层响应式,支持数组和 Map/Set 等特殊对象。
  • 优化
    • 使用 RefImplComputedRefImpl 类实现更高效的内存管理。
    • 针对不同类型(基本类型、对象、数组)做了特殊处理。

2. 功能完整性

特性原生实现Vue3 实现
基础响应式✅ 支持 .value 读写✅ 支持 .value 读写
计算属性✅ 基础实现✅ 完整支持,含缓存和懒计算
浅层响应式(shallowRef)❌ 未实现✅ 支持
只读引用(readonly)❌ 未实现✅ 支持
自定义响应式(customRef)❌ 未实现✅ 支持
与组件生命周期集成❌ 需手动管理✅ 自动绑定和清理副作用
类型系统基础类型支持完整 TypeScript 集成

3. 性能优化

原生实现
  • 依赖收集:每次访问属性时都需遍历依赖列表。
  • 触发更新:直接触发所有依赖,无批量更新机制。
  • 内存管理:依赖关系可能无法被垃圾回收(如 WeakMap 使用不当)。
Vue3 实现
  • 批量更新:使用微任务队列(queueJob)合并多次更新,避免重复渲染。
  • 细粒度依赖:通过 TrackOpTypesTriggerOpTypes 区分不同操作类型。
  • 优化渲染
    • 基于 shouldTrack 条件判断是否收集依赖。
    • 使用 ReactiveFlags 标记特殊对象,避免重复代理。

4. 与 Vue 生态的集成

原生实现
  • 模板集成:需手动绑定 DOM 更新逻辑。
  • 生命周期:无自动清理机制,需手动管理副作用。
  • Vue 特性:不支持 watchprovide/inject 等。
Vue3 实现
  • 模板自动解包:在 <template> 中无需 .value
  • 生命周期钩子:自动绑定 setup() 和组件实例。
  • Vue 特性
    • watchwatchEffect 无缝协作。
    • 支持 toReftoRefs 等工具函数。

5. 边界情况处理

场景原生实现Vue3 实现
循环引用❌ 可能导致栈溢出✅ 通过 targetMap 避免
非响应式对象❌ 直接返回原始值✅ 通过 toRaw() 显式转换
响应式丢失❌ 需手动处理✅ 提供 toRefs() 保持响应式
数组变异方法❌ 需手动实现✅ 自动处理(如 pushsplice

6. 错误处理与调试

原生实现
  • 错误捕获:需手动添加 try...catch
  • 调试工具:无内置支持,需手动打印日志。
Vue3 实现
  • 错误处理
    • 通过 app.config.errorHandler 全局捕获副作用错误。
    • 计算属性错误会缓存并在访问时抛出。
  • 调试工具
    • Vue DevTools 支持响应式数据可视化。
    • onTrackonTrigger 钩子用于调试依赖关系。

总结

维度原生实现Vue3 实现
实现复杂度较低(基础功能)极高(完整生态)
性能基础优化高度优化(批量更新、缓存等)
功能完整性核心功能完整特性集
与框架集成深度集成(模板、生命周期等)
调试工具手动调试官方 DevTools 支持

原生实现适合学习响应式原理,但在生产环境中,建议使用 Vue3 官方实现以获得完整功能和性能保障。

除了 Proxy,还有哪些方法可以实现类似 ref 的功能?

在 JavaScript 中,除了使用 Proxy 实现响应式外,还可以通过以下几种方式实现类似 Vue3 ref 的功能。每种方法各有优缺点,下面我将逐一介绍并给出示例代码。

1. Object.defineProperty()

这是 Vue2 中使用的核心响应式机制,通过 getter/setter 拦截属性访问。

实现原理

  • 为对象的属性定义 getter 和 setter
  • 在 getter 中收集依赖,在 setter 中触发更新

示例代码

javascript

function ref(initialValue) {const refObject = {_value: initialValue,};Object.defineProperty(refObject, 'value', {get() {track(refObject, 'value');return this._value;},set(newValue) {this._value = newValue;trigger(refObject, 'value');},});return refObject;
}// 依赖收集和触发更新的实现与之前相同

优缺点

  • 优点:兼容性好(支持 IE9+)
  • 缺点:
    • 无法检测对象属性的添加或删除
    • 对数组的支持有限(需手动处理变异方法)
    • 只能劫持对象的属性,无法劫持整个对象

2. 发布-订阅模式(Event Emitter)

通过自定义事件系统实现响应式,属性变化时发布事件,依赖方订阅事件。

实现原理

  • 创建一个事件中心,管理事件的发布和订阅
  • ref 对象的 setter 触发事件,getter 可用于依赖收集

示例代码

javascript

class EventEmitter {constructor() {this.events = new Map();}on(event, callback) {if (!this.events.has(event)) {this.events.set(event, []);}this.events.get(event).push(callback);}off(event, callback) {if (!this.events.has(event)) return;const callbacks = this.events.get(event);const index = callbacks.indexOf(callback);if (index !== -1) callbacks.splice(index, 1);}emit(event, ...args) {if (!this.events.has(event)) return;this.events.get(event).forEach(callback => callback(...args));}
}function ref(initialValue) {const emitter = new EventEmitter();let _value = initialValue;return {get value() {// 收集依赖逻辑return _value;},set value(newValue) {_value = newValue;emitter.emit('change', newValue);},onChange(callback) {emitter.on('change', callback);},};
}// 使用示例
const count = ref(0);
count.onChange((newValue) => {console.log('Count changed to:', newValue);
});count.value = 1; // 输出: Count changed to: 1

优缺点

  • 优点:
    • 实现简单直观
    • 可扩展性强,可自定义各种事件
  • 缺点:
    • 手动管理事件订阅和取消订阅
    • 缺乏自动依赖收集,需显式调用 onChange

3. ES6 类 + 访问器属性

使用 ES6 类的 getter/setter 实现响应式包装。

实现原理

  • 创建一个类,将值存储在私有属性中
  • 通过 public getter/setter 控制值的读写

示例代码

javascript

class Ref {constructor(initialValue) {this._value = initialValue;this.deps = new Set();}get value() {// 收集依赖if (activeEffect) {this.deps.add(activeEffect);activeEffect.deps.push(this.deps);}return this._value;}set value(newValue) {this._value = newValue;// 触发更新this.deps.forEach(effect => effect());}
}function ref(initialValue) {return new Ref(initialValue);
}// 副作用函数
let activeEffect = null;
function effect(fn) {const effectFn = () => {activeEffect = effectFn;fn();activeEffect = null;};effectFn();return effectFn;
}// 使用示例
const count = ref(0);
effect(() => {console.log('Count is:', count.value);
});count.value = 1; // 输出: Count is: 1

优缺点

  • 优点:
    • 面向对象设计,结构清晰
    • 可通过继承扩展功能
  • 缺点:
    • 无法拦截对象内部属性的变化(只能拦截顶层 value)
    • 相比 Proxy,需要为每个 ref 创建一个类实例

4. RxJS(响应式编程库)

利用 RxJS 的 Observable 实现数据流管理。

实现原理

  • 使用 BehaviorSubject 存储值并发布变更
  • 通过订阅流来响应值的变化

示例代码

javascript

import { BehaviorSubject } from 'rxjs';function ref(initialValue) {const subject = new BehaviorSubject(initialValue);return {get value() {return subject.getValue();},set value(newValue) {subject.next(newValue);},subscribe(callback) {return subject.subscribe(callback);}};
}// 使用示例
const count = ref(0);
const subscription = count.subscribe((newValue) => {console.log('Count changed to:', newValue);
});count.value = 1; // 输出: Count changed to: 1
subscription.unsubscribe(); // 取消订阅

优缺点

  • 优点:
    • 强大的异步数据流处理能力
    • 丰富的操作符(map、filter、merge 等)
  • 缺点:
    • 学习曲线陡峭
    • 引入额外的依赖库(RxJS)

5. Symbol + 全局注册表

使用 Symbol 作为唯一标识符,结合全局注册表管理响应式对象。

实现原理

  • 使用 Symbol 作为每个 ref 的唯一标识
  • 通过全局注册表存储 ref 的值和依赖关系

示例代码

javascript

const REF_KEY = Symbol('ref');
const refRegistry = new Map();function ref(initialValue) {const refId = Symbol('refId');refRegistry.set(refId, {value: initialValue,deps: new Set(),});return {get value() {track(refId);return refRegistry.get(refId).value;},set value(newValue) {refRegistry.get(refId).value = newValue;trigger(refId);},};
}// 依赖收集和触发更新的实现
function track(refId) {if (activeEffect) {refRegistry.get(refId).deps.add(activeEffect);activeEffect.deps.push(refRegistry.get(refId).deps);}
}function trigger(refId) {refRegistry.get(refId).deps.forEach(effect => effect());
}// 副作用函数
let activeEffect = null;
function effect(fn) {const effectFn = () => {activeEffect = effectFn;fn();activeEffect = null;};effectFn();return effectFn;
}

优缺点

  • 优点:
    • 避免直接在对象上添加属性,保持对象纯净
    • 更好的内存管理(通过 WeakMap 可实现)
  • 缺点:
    • 全局注册表可能导致命名冲突
    • 调试困难,难以追踪依赖关系

总结对比

方法优点缺点
Proxy深层响应式、拦截能力强兼容性差(IE 不支持)
Object.defineProperty兼容性好只能劫持属性,无法劫持对象
发布-订阅模式实现简单、灵活需手动管理事件订阅
ES6 类面向对象设计、结构清晰只能拦截顶层属性
RxJS强大的异步处理能力学习曲线陡峭、引入额外依赖
Symbol+注册表保持对象纯净、避免属性冲突调试困难、全局状态管理复杂

在实际应用中,Vue3 选择 Proxy 是因为它提供了更强大的元编程能力,可以拦截对象的各种操作,实现深层响应式。而其他方法各有适用场景,例如需要兼容旧浏览器时可考虑 Object.defineProperty,处理复杂异步数据流时 RxJS 是不错的选择。

如何使用原生 JavaScript 实现 reactive 功能?

下面我将使用原生 JavaScript 实现一个类似 Vue3 中 reactive 的功能。reactive 的核心是创建一个深层响应式对象,对对象的所有嵌套属性都进行代理,当属性值变化时触发依赖更新。

实现思路

  1. 使用 ES6 Proxy:拦截对象的属性访问和修改操作

  2. 递归代理嵌套对象:确保深层属性也具有响应式能力

  3. 依赖收集与触发:使用 WeakMap 存储对象与依赖的映射关系

  4. 特殊处理

    • 避免重复代理同一对象
    • 处理数组的变异方法(如 push、splice)
    • 支持不可变对象(readonly)

原生 JavaScript 实现

javascript

// 存储依赖关系的 WeakMap
// targetMap: WeakMap<target, depsMap>
// depsMap: Map<key, Set<effect>>
const targetMap = new WeakMap();// 当前活跃的副作用函数
let activeEffect = null;// 创建响应式对象
function reactive(target) {// 如果不是对象类型,直接返回if (typeof target !== 'object' || target === null) {return target;}// 如果已经是代理对象,直接返回if (target[ReactiveFlags.IS_REACTIVE]) {return target;}// 创建代理return createProxy(target);
}// 创建代理
function createProxy(target) {// 检查是否已存在代理const existingProxy = getTargetProxy(target);if (existingProxy) {return existingProxy;}// 创建新代理const proxy = new Proxy(target, {get(target, key, receiver) {// 处理特殊标志if (key === ReactiveFlags.IS_REACTIVE) {return true;}// 获取属性值const value = Reflect.get(target, key, receiver);// 收集依赖track(target, key);// 如果值是对象,递归创建响应式代理if (typeof value === 'object' && value !== null) {return reactive(value);}return value;},set(target, key, newValue, receiver) {const oldValue = target[key];const result = Reflect.set(target, key, newValue, receiver);// 只有当值真正发生变化时才触发更新if (oldValue !== newValue && (oldValue === oldValue || newValue === newValue)) {trigger(target, key);}return result;},deleteProperty(target, key) {const hadKey = key in target;const result = Reflect.deleteProperty(target, key);// 如果属性存在且被成功删除,触发更新if (hadKey && result) {trigger(target, key);}return result;}});// 存储代理与原始对象的映射storeTargetProxy(target, proxy);return proxy;
}// 依赖收集
function track(target, key) {if (!activeEffect) return;// 获取目标对象的依赖映射let depsMap = targetMap.get(target);if (!depsMap) {targetMap.set(target, (depsMap = new Map()));}// 获取属性的依赖集合let dep = depsMap.get(key);if (!dep) {depsMap.set(key, (dep = new Set()));}// 将当前活跃的副作用添加到依赖集合中dep.add(activeEffect);// 同时将依赖集合添加到副作用的依赖列表中activeEffect.deps.push(dep);
}// 触发更新
function trigger(target, key) {const depsMap = targetMap.get(target);if (!depsMap) return;// 创建要执行的副作用集合的副本const effects = new Set();// 添加属性的依赖副作用if (depsMap.has(key)) {depsMap.get(key).forEach(effect => {effects.add(effect);});}// 执行所有副作用effects.forEach(effect => effect());
}// 创建副作用函数
function effect(fn) {const effectFn = () => {try {// 清除之前的依赖cleanup(effectFn);// 设置当前活跃的副作用activeEffect = effectFn;// 执行副作用函数return fn();} finally {// 重置当前活跃的副作用activeEffect = null;}};// 存储该副作用的依赖集合列表effectFn.deps = [];// 立即执行副作用以收集依赖effectFn();return effectFn;
}// 清除副作用的依赖
function cleanup(effectFn) {effectFn.deps.forEach(dep => {dep.delete(effectFn);});effectFn.deps.length = 0;
}// 特殊标志
const ReactiveFlags = {IS_REACTIVE: Symbol('is_reactive')
};// 存储原始对象与代理的映射(简化版)
const proxyMap = new WeakMap();function getTargetProxy(target) {return proxyMap.get(target);
}function storeTargetProxy(target, proxy) {proxyMap.set(target, proxy);
}// 示例用法
const state = reactive({count: 0,user: {name: 'Alice',age: 30}
});// 创建副作用监听 count 变化
effect(() => {console.log('Count changed:', state.count);
});// 修改 count 值
state.count = 1; // 输出: Count changed: 1
state.count = 2; // 输出: Count changed: 2// 嵌套对象也具有响应式能力
effect(() => {console.log('User name changed:', state.user.name);
});state.user.name = 'Bob'; // 输出: User name changed: Bob

核心功能解析

  1. Proxy 拦截器
    • get:收集依赖并递归代理嵌套对象
    • set:比较新旧值,仅在值变化时触发更新
    • deleteProperty:处理属性删除时的依赖更新
  2. 依赖收集系统
    • 使用 WeakMap<target, Map<key, Set<effect>>> 存储依赖关系
    • 每个属性对应一个依赖集合(Set)
  3. 副作用管理
    • effect 函数创建响应式副作用
    • activeEffect 全局变量跟踪当前执行的副作用
  4. 循环引用处理
    • 使用 proxyMap 避免重复代理同一对象
    • 通过 ReactiveFlags.IS_REACTIVE 标识已代理对象

进阶功能实现(可选)

1. 数组变异方法处理

javascript

// 拦截数组的变异方法
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(method => {const original = arrayProto[method];arrayMethods[method] = function(...args) {// 先执行原始方法const result = original.apply(this, args);// 通知变更const ob = this.__ob__;// push、unshift、splice 可能会添加新元素,需要对新元素进行响应式处理let inserted;switch (method) {case 'push':case 'unshift':inserted = args;break;case 'splice':inserted = args.slice(2);break;}if (inserted) ob.observeArray(inserted);// 触发更新ob.dep.notify();return result;};
});
2. 计算属性实现

javascript

function computed(getter) {let value;let dirty = true;const runner = effect(getter, {lazy: true,scheduler: () => {if (!dirty) {dirty = true;// 触发依赖于这个计算属性的副作用trigger(computedRef, 'value');}}});const computedRef = {[ReactiveFlags.IS_REACTIVE]: true,get value() {if (dirty) {value = runner();dirty = false;}track(computedRef, 'value');return value;},set value() {console.warn('Computed value is readonly');}};return computedRef;
}
`### 与 Vue3 reactive 的差异1. **功能完整性**:- 缺少 Vue3 的 `shallowReactive``readonly``toRaw` 等工具函数- 未处理特殊对象(如 Map、Set、Date 等)
2. **性能优化**- 没有批量更新机制(Vue3 使用微任务队列合并更新)- 未实现细粒度的依赖优化
3. **生态集成**- 没有与 Vue 组件生命周期的集成- 缺少 DevTools 支持
这个实现展示了 Vue3 reactive 的核心原理,但在生产环境中建议使用官方实现以获得完整功能和性能保障。

相关文章:

  • vim 的基本使用
  • vue+mitt的简便使用
  • Linux 简单模拟实现C语言文件流
  • 剑指offer13_剪绳子
  • [Protobuf]常见数据类型以及使用注意事项
  • MacroDroid安卓版:自动化操作,让生活更智能
  • Android第十一次面试补充篇
  • 力扣题解106:从中序与后序遍历序列构造二叉树
  • 雪花算法:分布式ID生成的优雅解决方案
  • LINUX 61 rsync定时同步;软链接
  • RAGflow详解及实战指南
  • 《C++初阶之入门基础》【C++的前世今生】
  • C++命名空间深度解析
  • 功能丰富的PDF处理免费软件推荐
  • 如何实现告警的自动化响应?
  • Java求职者面试题详解:Spring、Spring Boot、MyBatis技术栈
  • PyTorch——DataLoader的使用
  • Java八股文智能体——Agent提示词(Prompt)
  • IDEA,Spring Boot,类路径
  • 论文阅读(六)Open Set Video HOI detection from Action-centric Chain-of-Look Prompting
  • 免费下载微信小程序/绍兴百度推广优化排名
  • 成品网站w灬 源码1688三叶草/百度引流推广怎么收费
  • 建设一个怎样的自己的网站/产品运营方案
  • 中卫市住房建设局网站/专业关键词排名优化软件
  • 网络推广员为什么做不长/重庆seo招聘
  • 网站后台ftp账户/抖音竞价推广怎么做