在上一篇文章里我描述了 reactive 响应式的原理,但是 vue3 不止只有 reactive 能创建响应式的对象,它还有ref也能创建响应式对象。
那ref的响应式原理是与reactive一样的吗?
先说结论:是的!
我之前一直以为 ref 是 vue2 的Object.defineProperty的实现而且一直被误导了很久,甚至还在某次面试上大言不惭的说 ref 是基于Object.defineProperty实现的,现在想来还真是头铁呢!
ref 本身其实与 reactive 并无多大的区别,响应式也是 reactive 那一套(effect()、track()、trigger()),而设计出 ref 的原因只是因为 reactive 必须传入一个引用类型,因为 proxy 只能代理对象,而像是基础类型什么number string bool啥的它是没法代理的。所以本质上 ref 只是一层 ractive 的语法糖,通过包装成.value的对象进而被 Proxy 代理。
类似这样的:
function ref(value) {
// 把原始值转换为响应式对象(如果是对象)
const wrapper = {
get value() {
track(wrapper, "value"); // 收集依赖
return value;
},
set value(newVal) {
if (newVal !== value) {
value = newVal;
trigger(wrapper, "value"); // 触发依赖
}
},
};
return wrapper;
}
结论
ref 是 Vue 3 用来让基础类型响应式的语法糖,它的 .value 是响应系统的出口,底层实现并不再使用 Vue 2 的 Object.defineProperty,而是走统一的 Proxy + track/trigger 架构。