JavaScript — динамичный и мощный язык, широко используемый в процессе разработки веб-приложений. В этой статье вы узнаете о структурах данных mutable и immutable в JavaScript, их важности и использовании.

Неизменяемые структуры данных

Неизменяемые структуры данных — это типы данных, значения которых нельзя изменить. Эти типы создают новое значение вместо изменения существующего значения при назначении нового значения.

Примитивные типы данных

  • Нить
  • Число
  • логический
  • Неопределенный
  • Нулевой
  • BigInt
  • Символ
const str = "Hello";
const newStr = str.concat(", World!");
console.log(str); // "Hello" - Original string unchanged
console.log(newStr); // "Hello, World!" - A new string is created

const num = 5;
const newNum = num + 1;
console.log(num); // 5 - Original number unchanged
console.log(newNum); // 6 - A new number value is created

Изменяемые структуры данных

Типы данных объекта изменяемы. Это означает, что вы можете изменять их свойства и значения, затрагивая все объекты с одной и той же ссылкой.

Объект

  • Простой объект
  • Множество
  • Функция
  • Дата
  • Специальные структуры, такие как Map, Set, WeakMap, WeakSet
const arr = [1, 2, 3];
arr[1] = 4;
console.log(arr); // [1, 4, 3] - Directly modifying the array

const obj = { key: "value" };
obj.key = "newValue";
console.log(obj); // { key: "newValue" } - Directly modifying the object

Однако иногда вы можете захотеть использовать изменяемые объекты, как если бы они были неизменяемыми. В этом случае вы можете использовать внешние библиотеки (например, Immutable.js, Immer) или некоторые методы, доступные в самом языке (например, Object.assign, Array.prototype.slice, оператор распространения), чтобы рассматривать изменяемые объекты как неизменяемые.

Например, вы можете использовать оператор распространения для создания нового массива без изменения исходного массива:

const arr = [1, 2, 3];
const newArr = [...arr.slice(0, 1), 4, ...arr.slice(2)];
console.log(newArr); // [1, 4, 3]
console.log(arr); // [1, 2, 3] - Original array unchanged

Здесь мы создали новый массив без изменения исходного массива, что позволяет исходным данным вести себя так, как если бы они были неизменяемыми. С помощью этих методов вы можете использовать изменяемые структуры данных более предсказуемым и эффективным способом.

Redux и неизменяемые структуры данных

Redux — это популярная библиотека для управления состоянием в приложениях JavaScript, которая повышает производительность и предсказуемость вашего приложения за счет использования неизменяемых структур данных.

Использование неизменяемых данных в Redux основано на следующих принципах:

  1. Единственный источник правды: Redux хранит все состояние приложения в одном объекте JavaScript. Это дерево состояний является общим для всех компонентов, и состояние служит единым источником.
  2. Состояние только для чтения: дерево состояний неизменяемо (не может быть изменено напрямую) и доступно только для чтения. Когда вы хотите внести изменения в состояние, вы отправляете действие в Redux, которое затем используется для обновления состояния.
  3. Редюсеры: редукторы — это чистые функции, которые выполняют действия и возвращают новое состояние на основе текущего состояния. Вместо прямого изменения существующего состояния редьюсеры всегда возвращают новый объект состояния, придерживаясь принципа неизменности.

Redux обеспечивает использование неизменяемых данных с этими принципами, как показано ниже:

function counterReducer(state = 0, action) {
  switch (action.type) {
    case "INCREMENT":
      return state + 1; // Returning a new numeric value
    case "DECREMENT":
      return state - 1; // Returning a new numeric value
    default:
      return state;
  }
}

В приведенном выше примере мы не изменяем текущее состояние напрямую. Вместо этого мы создаем новое состояние, возвращая новое числовое значение для операций INCREMENT и DECREMENT.

Вот еще один пример Redux для состояния объекта:

function todoReducer(state = {}, action) {
  switch (action.type) {
    case "ADD_TODO":
      return {
        ...state,
        [action.id]: {
          id: action.id,
          text: action.text,
          completed: false,
        },
      }; // Updating the state by creating a new object
    case "TOGGLE_TODO":
      return {
        ...state,
        [action.id]: {
          ...state[action.id],
          completed: !state[action.id].completed,
        },
      }; // Updating the state by creating a new object
    default:
      return state;
  }
}

В этом примере мы не изменяем исходное состояние напрямую во время операций ADD_TODO и TOGGLE_TODO. Вместо этого мы обновляем состояние, создавая новые объекты с помощью оператора распространения (...).

Заключение

Понимание изменяемых и неизменяемых структур данных в JavaScript и их правильное использование может значительно повысить производительность, надежность и масштабируемость ваших приложений. В этой статье мы рассмотрели основные различия между изменяемыми и неизменяемыми структурами данных и несколько примеров использования этих структур.