一场关于 Vue3 的面试
最近给一个朋友做了一场前端开发工程师模拟面试,我们姑且叫他 小B 吧。小B 有三年左右的的 Vue3 开发经验。
面试过程中,我(为了方便描述对话,以下简称 老A)问了这样一个问题:
老A:你知道为什么 Vue3 使用
Ref创建的响应式变量,需要通过.value来访问和修改吗?
他愣了一下,脑袋快速思考,好像没有检索到更好的答案
小B: 这个......就是 Vue3 的语法吧,我平时都是这么用的。
我点点头
老A:这是个非常好的开始,既然你用过,我们不妨一起把这个问题拆开,一步步搞清楚它背后的原理。
从 Vue3 响应式系统说起
我问继续问道:
老A:你知道 Vue3 为什么要从 Vue2 的
Object.defineProperty切换到Proxy吗?小B: 因为 Proxy 可以监听到更多类型的变化,比如新增属性、数组索引等等。
我点头:
老A: 没错,而且
Proxy是直接对对象做代理,那你觉得 Vue3 能不能用Proxy来代理一个数字、字符串、布尔值这样的基本类型?”
他想了想
小B: Proxy 只能代理对象吧?
老A:对了。所以 Vue3 面临一个问题:基本类型(primitive)没法直接变成响应式。
ref 的设计动机
我继续输出:
老A:这时候
ref这个 API 就诞生了。你可以理解为,ref(0)实际上返回了一个带有.value的对象,真实的值存储在这个.value里。
我简单在草纸上写了三行代码:
const count = ref(0);
console.log(count.value); // 读取
count.value = 1;          // 修改
他点了点头:“对,这个我用过。”
老A: 而 Vue3 的响应式追踪,依赖收集,和视图更新,全部基于对这个
.value的getter和setter进行拦截实现。
我停顿了一下,看着小B:
老A: 所以为什么需要
.value呢?
他笑了:
小B:因为值必须藏在对象里,Proxy 才能监听!
我竖起大拇指:“完全正确!”
reactive 和 ref 的区别
为了让他理解得更透彻,我又问了个问题:
老A: 那
reactive和ref有什么区别?”小B:
reactive是用来处理对象的,直接可以改属性;ref是处理基本类型的,要用.value。
我想他这次真的理解了,我补充说:
老A: 对。 因为
reactive返回的就是Proxy过的对象,不需要额外.value。但是基本类型不行,必须包装成对象——这就是ref。
然后我给他看了两段代码对比:
const state = reactive({ count: 0 });
state.count++;
const num = ref(0);
num.value++;
这两套写法,Vue3 都是通过 Proxy 实现响应式,但基本类型必须额外包一层。
为什么不直接统一语法?
小B 看老A 讲这么详细,也放开了, 追问:
小B: 那为啥 Vue3 不统一一下呢?比如都能直接用变量名,不用
.value。”老A:这个问题问得好。Vue 团队也想过,甚至 Vue3.3 已经引入了
ref sugar,可以用ref:语法省略.value,但这种语法是可选的,不是强制的。 最根本的原因在于:
明确语义,有利于代码提示和类型推导。 
不同的响应式对象有不同的行为, .value是一种安全的区分。
保持性能和一致性。 
继续补充:
老A: 其实很多 Vue 高手一开始也觉得
.value繁琐,但当你理解了它的设计哲学,就会觉得这是个合理的权衡。
他点点头:“原来如此。”
总结与延伸
所以我们回到最初的问题,Vue3 为什么 ref 变量需要 .value:
- 
Proxy 无法直接代理基本类型,必须包装成对象。 
- 
Vue3 需要通过.value 才能做依赖追踪和视图更新。 
- 
.value提供了明确语义,便于类型提示和维护。
未来如果用 <script setup> 和 ref sugar,可以省略 .value,但你要清楚省略的背后依然有这个机制在支撑。
技术的提升往往就藏在对"为什么"的好奇心里。
 
  
 
 
  
 

还没有人评论 快来占位置吧