JavaScript中的可变和不可变

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 数组没有被修改,所以这是一个不可变操作。

使用不可变数据结构的好处

提高可预测性

由于不可变数据无法更改,意外修改的可能性降低,从而减少了出现错误的风险。

与基于不可变性的库的兼容性

ReactRedux 这样的库通常是以不可变数据为设计理念的,这在正确使用时可以简化状态管理。

使用 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.freezedeepFreeze 可以用来防止对象的修改。
  • 使用不可变数据可以使代码更具可预测性且更不容易出错。

不可变设计可以增强代码的安全性和可读性,请好好利用它!

您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。

YouTube Video