← Назад к вопросам

Какие знаешь мутирующие функции?

1.8 Middle🔥 191 комментариев
#JavaScript Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI4 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Мутирующие функции в JavaScript

В JavaScript мутирующими (или мутабельными) называются функции и методы, которые изменяют исходный объект или массив, а не возвращают новую копию. Их важно знать, чтобы избежать неожиданных побочных эффектов, особенно при работе с React, Redux или в функциональном программировании.

Основные категории мутирующих функций

1. Методы массивов

Самый частый источник мутаций. Ключевые примеры:

// Мутирующие методы массивов
const arr = [1, 2, 3, 4, 5];

arr.push(6);        // Добавляет элемент в конец
arr.pop();          // Удаляет последний элемент
arr.shift();        // Удаляет первый элемент
arr.unshift(0);     // Добавляет элемент в начало
arr.splice(2, 1, 99); // Удаляет/заменяет элементы
arr.sort();         // Сортирует на месте
arr.reverse();      // Переворачивает массив на месте
arr.fill(0);        // Заполняет все элементы значением

Важный нюанс: sort() и reverse() мутируют исходный массив, хотя иногда это забывают:

const sorted = arr.sort(); // arr изменился, sorted ссылается на тот же массив

2. Методы объектов

Хотя объекты по своей природе мутабельны, некоторые методы явно их изменяют:

const obj = { a: 1, b: 2 };

Object.assign(obj, { c: 3 }); // Добавляет свойства в obj
delete obj.b;                  // Удаляет свойство
obj.d = 4;                     // Прямое присваивание - тоже мутация

3. Другие структуры данных

В ES6+ появились новые мутирующие методы:

// Map и Set
const map = new Map();
map.set('key', 'value'); // Мутирует Map
map.delete('key');

const set = new Set();
set.add(1);              // Мутирует Set
set.clear();

Иммутабельные альтернативы

Для избежания мутаций используйте следующие подходы:

// Вместо мутации создавайте новые массивы
const original = [1, 2, 3];

// Спред-оператор
const newArray = [...original, 4];

// map, filter, slice
const withoutFirst = original.slice(1);
const doubled = original.map(x => x * 2);

// Object.assign с пустым объектом
const newObj = Object.assign({}, original, { updated: true });

// Спред для объектов (ES2018+)
const updatedObj = { ...original, newProp: 'value' };

Практическое значение

В React мутации состояния напрямую могут привести к:

  • Неправильным ререндерам
  • Сложностям отслеживания изменений
  • Багам в shouldComponentUpdate
// ❌ Плохо - мутация состояния
this.state.items.push(newItem);
this.setState({ items: this.state.items });

// ✅ Хорошо - иммутабельное обновление
this.setState(prevState => ({
  items: [...prevState.items, newItem]
}));

В Redux редукторы должны быть чистыми функциями:

// ❌ Мутирующий редуктор
function badReducer(state = [], action) {
  state.push(action.payload); // Мутация!
  return state;
}

// ✅ Иммутабельный редуктор
function goodReducer(state = [], action) {
  return [...state, action.payload];
}

Специфические случаи и исключения

  1. Методы, которые кажутся иммутабельными, но это не всегда так:

    // concat обычно возвращает новый массив
    const newArr = arr.concat([6]); // Иммутабельно
    
    // Но если элементы - объекты, они остаются ссылками
    const objects = [{id: 1}];
    const newObjects = objects.concat({id: 2});
    objects[0].id = 999; // Изменение затронет и objects[0], и newObjects[0]
    
  2. Глубокая мутация vs поверхностная:

    const nested = { data: { items: [1, 2, 3] } };
    const shallowCopy = { ...nested };
    shallowCopy.data.items.push(4); // Мутирует оригинальный массив items!
    

Рекомендации по работе

  • Всегда проверяйте документацию метода на мутабельность
  • Используйте линтеры с правилами типа no-param-reassign
  • Для сложных структур используйте библиотеки типа Immer:
    import produce from 'immer';
    
    const nextState = produce(currentState, draft => {
      draft.items.push(newItem); // Кажется мутацией, но работает иммутабельно
    });
    

Мутирующие функции имеют право на существование (они часто эффективнее по памяти и скорости), но требуют осознанного применения. Ключ к успеху - четкое понимание, где и когда вы меняете данные, и выбор подходящей стратегии для каждой конкретной задачи.