Изменяемые и неизменяемые значения в 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-канал.