Изменяемые и неизменяемые значения в JavaScript

Изменяемые и неизменяемые значения в JavaScript

Эта статья объясняет концепции изменяемых и неизменяемых данных в JavaScript.

YouTube Video

Изменяемые и неизменяемые значения в JavaScript

Что такое изменяемое (mutable)?

Изменяемое означает, что значение может быть изменено. Объекты и массивы, которые являются ссылочными типами, являются типичными примерами изменяемых структур данных.

Пример изменяемого объекта

1let person = { name: "Alice", age: 25 };
2person.age = 26;
3console.log(person); // { name: "Alice", age: 26 }

В этом коде свойство age объекта person изменяется с 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)?

Неизменяемое означает, что значение не может быть изменено. Примитивные типы по своей сути являются неизменяемыми.

Пример неизменяемого примитивного типа

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 могут быть использованы для предотвращения изменений объектов.
  • Использование неизменяемых данных обеспечивает более предсказуемый и менее подверженный ошибкам код.

Неизменяемый дизайн повышает безопасность и читаемость кода, поэтому используйте его с умом!

Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.

YouTube Video