Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Почему можно что-нибудь сделать с мутабельными типами данных?
Вопрос о мутабельности - это один из фундаментальных принципов в программировании. В JavaScript есть мутабельные (изменяемые) и иммутабельные (неизменяемые) типы. Понимание различия критично для написания надёжного кода.
Мутабельные vs Иммутабельные типы
// Примитивы - ИММУТАБЕЛЬНЫ
let num = 5;
num = 10; // создали новое значение, старое не изменилось
let str = "hello";
str = "hello world"; // создали новую строку
// Объекты - МУТАБЕЛЬНЫ
const obj = { name: "John" };
obj.name = "Jane"; // изменили существующий объект
obj.age = 30; // добавили новое свойство
const arr = [1, 2, 3];
arr[0] = 99; // изменили элемент массива
arr.push(4); // добавили элемент
Разница: примитивы вы не можете изменить на месте, объекты можете.
Почему мутабельность проблематична
1. Непредсказуемые побочные эффекты
// Проблема
function doubleNumbers(arr) {
return arr.map(n => n * 2); // OK
}
const numbers = [1, 2, 3];
const doubled = doubleNumbers(numbers);
console.log(numbers); // [1, 2, 3] - не изменился
// НО
function doubleArrayMutating(arr) {
arr[0] = arr[0] * 2; // мутируем!
arr[1] = arr[1] * 2;
arr[2] = arr[2] * 2;
return arr;
}
const numbers2 = [1, 2, 3];
const doubled2 = doubleArrayMutating(numbers2);
console.log(numbers2); // [2, 4, 6] - изменился! Неожиданно!
2. Баги в React из-за мутации
// ПЛОХО - мутируем state
function BadComponent() {
const [user, setUser] = useState({ name: "John", age: 30 });
const handleNameChange = (newName: string) => {
user.name = newName; // МУТАЦИЯ!
setUser(user); // React не заметит изменений
};
return (
<>
<p>{user.name}</p>
<button onClick={() => handleNameChange("Jane")}>Change</button>
</>
);
// Текст НЕ обновится, потому что объект был изменён на месте
// React сравнивает ссылки, не содержимое
}
// ХОРОШО - создаём новый объект
function GoodComponent() {
const [user, setUser] = useState({ name: "John", age: 30 });
const handleNameChange = (newName: string) => {
setUser(prev => ({ ...prev, name: newName })); // новый объект
};
return (
<>
<p>{user.name}</p>
<button onClick={() => handleNameChange("Jane")}>Change</button>
</>
);
// Текст обновится, потому что это новый объект
}
Правило: не мутируй state
// Массивы
const [items, setItems] = useState([1, 2, 3]);
// ПЛОХО
items.push(4);
setItems(items);
// ХОРОШО
setItems([...items, 4]);
setItems(prev => [...prev, 4]);
// Удаление
// ПЛОХО
items.splice(0, 1);
setItems(items);
// ХОРОШО
setItems(items.filter((_, i) => i !== 0));
setItems(prev => prev.slice(1));
// Изменение элемента
// ПЛОХО
items[0] = 99;
setItems(items);
// ХОРОШО
setItems(items.map((v, i) => i === 0 ? 99 : v));
setItems(prev => [99, ...prev.slice(1)]);
Объекты и вложенные структуры
const [user, setUser] = useState({
name: "John",
address: {
city: "Moscow",
zip: "123456"
}
});
// ПЛОХО - мутируем вложенный объект
user.address.city = "SPB";
setUser(user);
// ХОРОШО - создаём новые объекты на каждом уровне
setUser({
...user,
address: {
...user.address,
city: "SPB"
}
});
// ИЛИ используйте immer
import produce from 'immer';
setUser(produce(draft => {
draft.address.city = "SPB";
}));
Методы массивов: мутирующие vs безопасные
const arr = [1, 2, 3, 4, 5];
// МУТИРУЮЩИЕ методы (изменяют оригинальный массив)
arr.push(6); // добавляет в конец
arr.pop(); // удаляет последний
arr.shift(); // удаляет первый
arr.unshift(0); // добавляет в начало
arr.splice(0, 1); // удаляет и заменяет
arr.reverse(); // разворачивает
arr.sort(); // сортирует
arr.fill(0); // заполняет значением
// БЕЗОПАСНЫЕ методы (возвращают новый массив)
const arr2 = arr.slice(0, 2); // подмассив
const arr3 = arr.concat([6, 7]); // объединение
const arr4 = arr.map(x => x * 2); // трансформация
const arr5 = arr.filter(x => x > 2); // фильтрация
const arr6 = [0, ...arr]; // добавление в начало
const arr7 = [...arr, 6]; // добавление в конец
Когда можно мутировать
1. Объекты которые только создали
function createUser(name, email) {
const user = {}; // новый объект
user.name = name; // мутация OK - никто не использует
user.email = email;
user.id = Math.random();
return user; // возвращаем сформированный объект
}
2. Внутри функции перед возвратом
function processArray(arr) {
const result = [...arr]; // копируем
result.sort(); // мутируем копию
return result; // возвращаем
}
const original = [3, 1, 2];
const sorted = processArray(original);
console.log(original); // [3, 1, 2] - не изменился
console.log(sorted); // [1, 2, 3]
3. Локальные переменные в функции
function calculateSum(arr) {
let sum = 0; // локальная переменная
for (let num of arr) {
sum += num; // мутируем локальную переменную
}
return sum; // OK
}
Структурное копирование
// Поверхностное копирование (shallow copy)
const original = { name: "John", address: { city: "Moscow" } };
const copy1 = { ...original };
const copy2 = Object.assign({}, original);
copy1.name = "Jane"; // OK
copy1.address.city = "SPB"; // ПЛОХО - изменит и original!
// Глубокое копирование (deep copy)
const deepCopy = JSON.parse(JSON.stringify(original));
// ВНИМАНИЕ: теряются функции, Date, undefined, etc
// Лучше - используйте проверенные библиотеки
import { cloneDeep } from 'lodash';
const safeCopy = cloneDeep(original);
Immutability библиотеки
// Immer - самая популярная
import produce from 'immer';
const state = { user: { name: "John" } };
const newState = produce(state, draft => {
draft.user.name = "Jane"; // можно мутировать draft
});
// Вернёт новый объект если что-то изменилось
// Использование в React
setUser(produce(user => {
user.name = "Jane";
user.age = 31;
}));
Правила для безопасного кода
// 1. Не мутируй props
function Button({ disabled, onClick }: Props) {
disabled = false; // ПЛОХО - не повлияет, но плохая практика
return <button disabled={disabled} />
}
// 2. Не мутируй state напрямую
const [count, setCount] = useState(0);
count = 5; // ПЛОХО
// 3. При работе с массивами в state используй новые массивы
setItems([...items, newItem]); // ХОРОШО
// 4. Для сложных объектов используй immer
setUser(produce(draft => {
draft.profile.name = "Jane";
}));
// 5. Если нужна мутация - копируй перед ней
const arr = [1, 2, 3];
const sorted = [...arr].sort(); // копируем, потом мутируем
Итоговый принцип
В современном JavaScript и React - избегайте мутаций state и props. Это главное правило для надёжного и предсказуемого кода. Мутирующие методы нужны только для локальных переменных или новых объектов до их использования.