JavaScript中的可变和不可变
本文解释了JavaScript中可变和不可变的概念。
YouTube Video
JavaScript中的可变和不可变
什么是可变(Mutable)?
**可变(Mutable)意味着一个值可以被修改。对象和数组是引用类型(reference types)**的典型例子,也是典型的可变数据结构。
可变对象示例
1let person = { name: "Alice", age: 25 };
2person.age = 26;
3console.log(person); // { name: "Alice", age: 26 }
在这个代码中,person对象的age属性从25更改为26。由于对象是通过引用传递的,因此修改了person变量中存储的内存地址的内容。
可变数组示例
1let numbers = [1, 2, 3];
2numbers.push(4);
3console.log(numbers); // [1, 2, 3, 4]
在这个代码中,使用push方法向原数组添加了一个新元素4。这修改了原数组,因此是一个可变操作。
在函数中的示例
1// Function to append a value to an array
2function append(arr, value) {
3 arr.push(value); // Modify the original array
4 console.log(arr);
5}
6
7let numbers = [1, 2, 3];
8append(numbers, 4);
9
10console.log(numbers); // [1, 2, 3, 4] (original array is modified)
在函数中执行可变操作时,原数组也会被修改。
什么是不可变(Immutable)?
**不可变(Immutable)**意味着一个值不能被修改。**基本类型(Primitive types)**本质上是不可变的。
不可变基本类型的示例
1let str = "hello";
2str[0] = "H";
3console.log(str); // "hello"
尝试将字符串str的第一个字符改为H失败,因为字符串是不可变的。
在函数中的示例
1// Function to increment a number
2function increment(num) {
3 num++; // This modifies only the local copy of num
4 console.log(num);
5}
6
7let number = 10;
8increment(number);
9
10console.log(number); // 10 (original number remains unchanged)
由于数字是不可变的,在函数内部的操作不会影响原始变量。
数组上的不可变操作
数组是可变的,但创建一个新数组而不是修改原数组可以实现不可变操作。
1// Create an array of numbers
2let numbers = [1, 2, 3];
3
4// Create a new array by spreading the original and adding a new element
5let newNumbers = [...numbers, 4];
6
7console.log(numbers); // [1, 2, 3] (original array is unchanged)
8console.log(newNumbers); // [1, 2, 3, 4] (new array with an added element)
在这里,扩展语法 (...) 被用来创建一个新的数组 newNumbers。由于原始的 numbers 数组没有被修改,所以这是一个不可变操作。
使用不可变数据结构的好处
提高可预测性
由于不可变数据无法更改,意外修改的可能性降低,从而减少了出现错误的风险。
与基于不可变性的库的兼容性
像 React 和 Redux 这样的库通常是以不可变数据为设计理念的,这在正确使用时可以简化状态管理。
使用 Object.freeze 使对象不可变
Object.freeze 可以用来防止对象的修改。
1// Create a frozen object (properties cannot be modified)
2const person = Object.freeze({ name: "Alice", age: 25 });
3
4// Attempt to modify a property (ignored in non-strict mode, error in strict mode)
5person.age = 26;
6
7console.log(person); // { name: "Alice", age: 25 }
但是,Object.freeze 执行的是 浅冻结,这意味着嵌套对象的属性仍然是可变的。
1// Create a frozen object with a nested object
2const user = Object.freeze({ profile: { name: "Bob" } });
3
4// Attempt to modify a nested property (this works because Object.freeze() is shallow)
5user.profile.name = "Charlie";
6
7console.log(user.profile.name); // "Charlie" (nested object is still mutable)
要创建一个完全不可变的对象,需要进行 深冻结。
1// Function to deeply freeze an object, making all nested objects immutable
2function deepFreeze(obj) {
3 Object.keys(obj).forEach(key => {
4 if (typeof obj[key] === "object" && obj[key] !== null) {
5 deepFreeze(obj[key]); // Recursively freeze nested objects
6 }
7 });
8 return Object.freeze(obj); // Freeze the top-level object
9}
10
11// Create a deeply frozen object
12const user = deepFreeze({ profile: { name: "Bob" } });
13
14// Attempt to modify a nested property (ignored)
15user.profile.name = "Charlie";
16
17console.log(user.profile.name); // "Bob" (unchanged due to deep freeze)
总结
- 可变 数据是可以修改的,包括对象和数组。
- 不可变 数据是不可修改的,包括字符串和数字等基本类型。
- 使用扩展语法或
map可以实现不可变数据操作。 Object.freeze和deepFreeze可以用来防止对象的修改。- 使用不可变数据可以使代码更具可预测性且更不容易出错。
不可变设计可以增强代码的安全性和可读性,请好好利用它!
您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。