Appearance
const常量到底是值不可变还是地址不可变
const常量到底是值不可变还是地址不可变?
先说答案:地址不可变。
准确的说是:对于原始数据类型(如数字、字符串、布尔值等),是值不可变。对于复杂数据类型(如对象和数组),是地址不可变。
js
const a = 10; // 对于原始类型,不能重新赋值
a = 20; // 错误
const obj = {key: 'value'}; // 对于对象,可以改变其内容
obj.key = 'new value'; // 正确
obj = {}; // 错误,不能重新赋值
const arr = [1, 2, 3]; // 对于数组,可以改变其内容
arr.push(4); // 正确
arr = []; // 错误,不能重新赋值
原理
原始类型体积小,通常存储在栈中。
在 JavaScript 引擎实现层面(如 V8),这些值通常以一种高效的格式直接存放在栈帧或寄存器中,或者作为内联值处理,访问速度快。
const 锁定的是变量绑定(binding),而不是值本身。
对于原始类型,因为值是直接存储的,所以 const 实际上锁定了“值”。
复杂类型(对象、数组等)主要存储在堆中,栈中只保存引用地址。
对象、数组、函数等是动态结构,大小不固定,因此通常分配在堆上。
栈中保存的是指向堆中数据的指针(引用地址)。这样设计可以提高内存使用的灵活性,避免栈溢出问题。
所以 const 锁定的是引用地址,内容仍可修改。
Ps: 上面提到的“栈”和“堆”的区别是对底层实现的一种近似描述,并不是 JavaScript 语言规范中的标准说法。
冻结对象
因为用 const 定义了一个对象,也不能阻止你修改它的属性。
如果希望对象绝对不可变,可以使用 Object.freeze(obj) 或其他深冻结方法。
js
const person = {
name: "Alice",
age: 25,
address: {
city: "Beijing",
zip: "100000"
}
};
// 冻结对象
Object.freeze(person);
// "增删改查"属性,不会生效
person.name = "Bob";
person.gender = "male";
delete person.age;
但是注意,Object.freeze(obj) 是浅冻结。它只会冻结对象自身的第一层属性,如果某个属性是对象,它的内容依然可以被修改。
js
person.address.zip = "1001"; // 可以修改成功