You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3中修改非响应式属性为何呈现响应式效果?

问题解析:Vue3中修改本地非响应式对象却触发watch捕获修改后值的原因

核心原因

这一现象是引用类型的内存特性与Vue异步更新队列的执行时机共同作用的结果,具体拆解如下:

1. 引用类型的共享内存指向

local_variable是一个普通JS对象(引用类型),当你将它赋值给响应式对象的data属性时:

this.data = local_variable;

此时this.data和local_variable指向同一块内存地址中的对象。后续修改local_variable.name,本质上就是直接修改this.data指向的对象的属性——两者是同一个对象,只是引用名不同。

2. Vue异步更新的执行顺序

Vue的响应式更新(包括watch回调的触发)并非同步执行,而是会被推入微任务队列,等待当前所有同步代码执行完毕后才会执行。在你的第一个示例中:

  • 同步代码先完成赋值操作,触发响应式依赖变更,但watch回调不会立即执行;
  • 紧接着同步执行local_variable.name = 'Immediate: updated',直接修改了共享对象的属性;
  • 当所有同步代码执行完毕后,微任务队列中的watch回调才会触发,此时读取reactiveObject.data?.name自然是已经修改后的值。

3. 延迟修改的差异

当在赋值与修改之间加入延迟(比如setTimeout)时,修改操作会被推入宏任务队列。而JS的事件循环中,微任务会优先于宏任务执行:

  • 同步代码执行赋值后,watch回调进入微任务队列;
  • 延迟修改操作进入宏任务队列,需等待微任务全部执行完成后才会触发;
  • 因此watch回调执行时,读取的是对象的初始值,后续的修改因为local_variable不是响应式对象,无法触发新的watch回调。

验证示例

无延迟的代码

<script setup>
import { reactive, watch } from 'vue';

class MyClass {
  data = null;

  assignAndUpdateImmediate() {
    const local_variable = { name: 'Immediate: initial' };
    this.data = local_variable;
    local_variable.name = 'Immediate: updated';
  }
}

const reactiveObject = reactive(new MyClass());

watch(() => reactiveObject.data?.name, (newName, oldName) => {
  console.log(`WATCHER: "${oldName}" -> "${newName}"`);
});

reactiveObject.assignAndUpdateImmediate();
</script>

<template></template>

输出:

WATCHER: "undefined" -> "Immediate: updated"

带延迟的代码

<script setup>
import { reactive, watch } from 'vue';

class MyClass {
  data = null;

  assignAndUpdateDelayed() {
    const local_variable = { name: 'Immediate: initial' };
    this.data = local_variable;
    setTimeout(() => {
      local_variable.name = 'Immediate: updated';
    }, 0);
  }
}

const reactiveObject = reactive(new MyClass());

watch(() => reactiveObject.data?.name, (newName, oldName) => {
  console.log(`WATCHER: "${oldName}" -> "${newName}"`);
});

reactiveObject.assignAndUpdateDelayed();
</script>

<template></template>

输出:

WATCHER: "undefined" -> "Immediate: initial"

内容的提问来源于stack exchange,提问作者borndeprecated

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:57:02