Vue 3 响应式系统基于 Proxy,支持对象、数组、Map、Set 等几乎所有 JS 类型;Date、RegExp 等仅读取响应;函数不响应;未包装或违反约束(如直接挂载属性、索引改数组)则不响应;可用 reactive/ref 接入响应链,markRaw 避免代理开销。

Vue.js 的响应式系统不是“适配”非原生 JS 数据对象,而是主动包裹、代理并增强它们——它不依赖对象是否“原生”,而取决于你用什么方式创建和操作它。
哪些数据能被 Vue 自动转为响应式
Vue 3 使用 Proxy,可响应几乎所有 JavaScript 值类型:
- 普通对象(
{})、数组([])、Map、Set、WeakMap、WeakSet —— 全部支持,且新增/删除属性、动态键、迭代操作(如for...of、keys())都能被精确捕获; - Date、RegExp、Promise 等内置对象也能被代理,但通常只用于读取场景(修改其内部状态一般不触发视图更新,因语义上非“数据状态”);
- 函数本身不会被转为响应式(函数是行为,不是状态),但可作为响应式对象的属性存在。
哪些数据默认不响应?为什么
不是“Vue 不支持”,而是未经过响应式包装或违反响应式约束:
-
直接挂到实例上的新属性:比如
this.newProp = 'x'—— Vue 初始化时未劫持该 key,后续赋值无 getter/setter; -
通过索引直接修改数组:如
arr[0] = 'new'—— Vue 3 的 Proxy 能捕获,但 Vue 2 的Object.defineProperty无法监听,属历史限制; -
使用不可变操作返回新对象:如
list.filter(...)、[...arr]—— 原数组没变,响应式依赖仍绑定在旧引用上; -
第三方库创建的“黑盒对象”:如 ECharts 实例、CanvasRenderingContext2D —— 它们不是纯数据,且内部结构复杂,Proxy 可能触发意外副作用,此时应配合
markRaw主动排除。
如何让非响应式数据“变响应”
关键不在“转换数据”,而在正确接入响应式链条:
立即学习“前端免费学习笔记(深入)”;
- 对已存在的普通对象,用
reactive()包裹(仅限对象/数组); - 对原始值或需跨上下文访问的值,用
ref(),JS 中通过.value操作,模板中自动解包; - 向已有响应式对象添加新属性,用
Vue.set(obj, key, val)(Vue 2)或直接赋值(Vue 3 Proxy 支持); - 批量更新对象属性,避免
Object.assign(this.obj, newData),改用this.obj = {...this.obj, ...newData}或Object.assign({}, this.obj, newData)创建新响应式引用。
特殊数据类型的处理要点
Vue 对集合类做了专门适配,但行为有别于普通对象:
-
Map / Set:支持
set()、add()、delete()、clear()等方法触发更新;forEach、values()、entries()也受代理控制; -
嵌套结构:
reactive({ a: { b: 1 } })中,a是响应式,a.b也是响应式(深度代理);但若写成ref({ b: 1 }),则.value.b默认不响应,需手动reactive或嵌套ref; -
大型静态数据(如图标配置、语言包):用
markRaw()显式标记,避免无谓代理开销,同时保留其作为普通 JS 对象的性能与兼容性。


















