明明用const定义了响应式变量(比如const name = ref("小明")),为什么还能通过name.value = "小红"修改它的值?
刚学 Vue3 的小伙伴,大概率会遇到这个 "反常识" 的困惑:
明明用const定义了响应式变量(比如const name = ref("小明")),为什么还能通过name.value = "小红"修改它的值?
要知道在普通 JavaScript 里,const声明的变量可是 "一旦赋值就不能改" 的啊!今天咱们用 5 分钟把这个问题讲透,从此对 Vue3 的响应式不再迷茫。
先搞懂:普通 JS 里的 const 和 let 到底差在哪?
在聊 Vue3 之前,得先回顾下基础 ------ 很多人其实没真正搞懂const的 "不能改" 到底指什么。
比如这段普通 JS 代码:
javascript
// 用let声明的变量:可以重新赋值
let userName1 = "小明";
userName1 = "小红"; // 合法,没问题
// 用const声明的变量:不能重新赋值
const userName2 = "小明";
userName2 = "小红"; // 报错!Assignment to constant variable
这里的关键是:const限制的是 "变量的引用",而不是 "变量的值" 。
如果const声明的是 "引用类型"(比如对象、数组),情况就不一样了:
javascript
// const声明对象:变量本身的引用不能改,但对象内部的属性可以改
const user = { name: "小明" };
user.name = "小红"; // 合法!不会报错
user.age = 18; // 也合法!
// 但不能给user重新赋一个新对象
user = { name: "小刚" }; // 报错!因为改变了变量的引用
对于有 C 语言基础的同学来说,这和指针的逻辑很像:const 修饰的变量就像 const 指针(如 char* const p),指针变量 p 本身存储的内存地址不能改(对应 JS 里变量的引用不能变),但指针指向的内存空间里的数据可以改(对应 JS 里引用类型内部的属性能改)。一句话总结:const就像给变量上了 "锁",但只锁 "变量指向谁",不锁 "指向的内容里有什么" 。
回到 Vue3:ref 到底做了什么?
理解了普通 JS 的规则,再看 Vue3 的ref就简单了。
当我们写const name = ref("小明")时,Vue3 到底干了什么?
其实ref("小明")会帮我们创建一个 "响应式容器对象" ,你可以把它想象成一个 "装着值的小盒子",结构大概是这样的:
javascript
// ref("小明")的本质:返回一个包含value属性的对象
const name = {
value: "小明" // 我们要修改的,其实是这个盒子里的value
};
所以:
- 我们用const声明name,是为了锁定 name 这个 "盒子" 本身------ 不让它被换成其他 "盒子"(比如不能再写name = ref("小刚"));
- 而name.value = "小红"修改的是盒子里的内容,并没有改变name指向的 "盒子",这完全符合const的规则。
用一张图更直观:

伪代码
const name = ref("小明") → name → [响应式盒子: { value: "小明" }]
name.value = "小红" → name还是指向同一个盒子 → [响应式盒子: { value: "小红" }]
name = ref("小刚") → 试图让name指向新盒子 → 报错!(const不允许)
再延伸:reactive 也是同样的道理吗?
对!reactive虽然不用写.value,但本质和ref一样,都是 "修改对象内部属性"。
比如:
vue
const user = reactive({ name: "小明" });
user.name = "小红"; // 合法!修改的是对象内部属性
user = reactive({ name: "小刚" }); // 报错!试图改变user的引用
甚至可以这么理解:ref其实是对reactive的 "封装",帮我们把基本类型(数字、字符串)变成了 "可以被跟踪的对象"。
最后总结:Vue3 里该怎么用 const 和 let?
记住一个核心原则:只要是响应式变量,就用 const;只有非响应式变量需要重新赋值时,才用 let。
具体场景:
变量类型 | 推荐声明方式 | 原因 |
---|---|---|
ref 创建的变量 | const | 只改.value,不改变量引用 |
reactive 创建的变量 | const | 只改对象内部属性,不改变量引用 |
非响应式且需要重新赋值的变量 | let | 比如普通名字切换let tempName = "小明"; tempName = "小红" |
函数(方法、钩子) | const | 函数不需要重新赋值,用 const 更安全 |
比如正确的写法:
vue
<script setup>
// 响应式变量:用const
const name = ref("小明");
const user = reactive({ name: "小明" });
// 方法:用const
const handleRename = () => {
name.value = "小红"; // 改内部属性,合法
user.name = "小红"; // 改内部属性,合法
};
// 非响应式且需要改的变量:用let
let tempName = "小明";
const handleTempRename = () => {
tempName = "小红"; // 需要重新赋值,用let
};
</script>
看到这里,你应该彻底明白为什么 Vue3 里到处都是const了吧?其实不是const"失效" 了,而是我们利用了 "对象引用不变,内部属性可改" 的特性,配合 Vue3 的响应式系统实现了数据更新。
下次再遇到这个疑问,就想想那个 "装值的小盒子"------ 你改的是盒子里的名字,不是盒子本身,所以const当然不会拦着你啦!