Реклама
Меморина
Меморина
Меморина

«Почему стоит перестать деструктурировать всё в JavaScript»

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

Обложка: «Почему стоит перестать деструктурировать всё в JavaScript»

Если вы пишете на JavaScript, скорее всего, деструктуризация — один из первых паттернов, который вы используете каждый день. Но что, если автоматическая деструктуризация делает код не короче, а труднее для чтения?

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

Ключевые выводы

Деструктуризация — инструмент, а не норма. Её стоит применять там, где она правда упрощает код, а не просто экономит символы.

Объект хранит контекст. project.status понятнее, чем голая переменная status, особенно в больших функциях.

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

Деструктурируйте позже, а не раньше. Сохраняйте исходный объект до тех пор, пока он действительно не понадобится в разобранном виде.

Каждая новая переменная — когнитивная цена. Если имя не добавляет смысла, лучше обратиться к свойству объекта напрямую.

Деструктуризация — не религия

Несколько лет назад Мэтт Смит деструктурировал почти всё: объекты, пропсы, параметры, возвращаемые значения. Если встречался объект — он его раскладывал. Это перестало быть осознанным решением и превратилось в привычку: так пишет «современный JavaScript».

Сейчас он всё ещё использует деструктуризацию, но уже не автоматически. Причина простая: возвращаясь к старому коду, Смит тратит больше времени, чем ожидает, чтобы понять, откуда взялась та или иная переменная. Ему приходится мысленно собирать исходный объект обратно, прежде чем разобраться, что происходит.

В какой-то момент до него дошло: он оптимизировал процесс написания, а не чтения. Экономия нескольких нажатий клавиш сегодня оборачивалась дополнительными минутами разбора завтра.

Не бойтесь повторов

Один из самых распространённых паттернов — вынесть поля из объекта, а потом передать их как пропсы в компонент:

С этим ничего не случилось. Но сегодня автор с большей вероятностью напишет так:

Да, здесь повторяется post. Но когда он вернётся к этому коду через месяц, ему не придётся вспоминать, откуда взялись title или author. Контекст остаётся на виду.

Объект несёт контекст

Это особенно заметно в длинных функциях. Представьте, что в начале файла вы написали:

			const {
  id,
  status,
  owner,
  createdAt,
  updatedAt,
} = project;
		

А сто строк ниже встретили такой код:

			// ...много строк...

saveAuditLog(owner);

// ...ещё больше строк...

if (status === "archived") {
  // ...
}
		

Моментальная пауза: «archived»… что именно? Сравните с вариантом, где объект сохраняет свою форму:

			if (project.status === "archived") {
  archive(project);
}

logger.info(project.status);
		

Объект по-прежнему несёт полезный контекст. Лишние символы редко замедляют чтение. А вот необходимость помнить, к какой сущности относится переменная, замедляет гораздо сильнее.

Вложенность лучше раскрывать поэтапно

Раньше автор считал вложенную деструктуризацию элегантной. Сейчас она часто кажется попыткой понять всю структуру объекта ещё до того, как начал решать задачу.

			const {
  user: {
    profile: { name, email },
  },
} = data;
		

Автор предпочитает писать иначе:

			const profile = data.user.profile;

const { name, email } = profile;
		

Так лучше отражается мышление о данных: сначала интересует профиль, а уже потом, если нужно, из него извлекают конкретные поля.

Деструктурируйте позже, а не раньше

С параметрами компонентов ситуация похожа. Для маленьких компонентов деструктуризация пропсов отлично работает:

Но по мере роста компонента автор чаще пишет так:

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

Каждая переменная — цена для читателя

Каждая локальная переменная просит читателя запомнить ещё одно имя. Иногда это стоит того, иногда — нет.

Если новая переменная обозначает осмысленную концепцию, автор с удовольствием её вводит. Имя вроде billingAddress становится частью словаря функции.

Но если автор просто превращает project.status в status, уверенности, что код стал читабельнее, нет. Полезное правило большого пальца: если деструктуризация даёт коду лучший словарь — использует её. Если она только экономит несколько символов — обычно нет.

Когда деструктуризация всё ещё уместна

Всё вышесказанное — не аргумент против деструктуризации. Автор по-прежнему применяет её постоянно.

			const { currentTarget } = event;

const { data } = response;
		

Эти случаи локальны, сфокусированы и убирают шум. Есть и другие исключения. При маппинге массива я спокойно пишу:

Объект существует всего несколько строк, поэтому автор не чувствует, что теряет контекст. Иногда имеет смысл даже переименовать извлечённое свойство: const { status: projectStatus } = project;.

Такое имя сохраняет больше контекста, чем просто status. Но если автор всё равно несёт имя объекта в переменную, часто оказывается, что project.status читается естественнее. Не нужно придумывать новое имя, а связь с объектом остаётся очевидной.

Разница в том, что автор больше не деструктурирует просто потому, что объект существует.

Главный вопрос

Автор всё ещё любит деструктуризацию. Есть множество мест, где она заметно очищает код. Просто он больше не хватается за неё автоматически.

Перед тем как убрать объект, он спрашивает себя: удаление объекта действительно облегчает понимание или просто делает код короче?

Если деструктуризация даёт коду лучший словарь — автор её использует. Если она только экономит несколько символов — обычно нет.
Мэтт Смитфронтенд-разработчик, автор блога All Things Smitty
Часто задаваемые вопросы
1
Что такое деструктуризация в JavaScript?

Это синтаксис для извлечения значений из объектов и массивов в отдельные переменные. Например, const { name } = user создаёт переменную name из свойства объекта user.

2
Почему автор считает, что деструктуризация может вредить читаемости?

Потому что извлечённые переменные теряют связь с исходным объектом. В больших функциях это заставляет читателя вспоминать, откуда взялась переменная, и мысленно восстанавливать контекст.

3
Когда деструктуризация всё ещё оправдана?

В локальных, сфокусированных фрагментах: извлечение currentTarget из события, data из ответа API, полей в коротких колбэках map или filter.

4
Стоит ли полностью отказаться от деструктуризации пропсов в React?

Нет. Для маленьких компонентов она по-прежнему удобна. Но в ростущих компонентах стоит рассмотреть сохранение объекта props до тех пор, пока не понадобится извлечь конкретные значения.

5
Какое простое правило помогает выбрать?

Спрашивайте: «Удаление объекта делает код понятнее или только короче?» Если ответ — «только короче», лучше оставить объект.

Выводы

Деструктуризация остаётся одним из самых полезных синтаксических улучшений JavaScript. Но удобство записи не должно превращаться в удобство только для автора. Читаемость кода измеряется не количеством символов, а скоростью, с которой человек понимает, что происходит.

Сохраняйте объекты там, где они несут контекст. Раскрывайте вложенность поэтапно. Вводите переменные, только если они добавляют смысла. И не забывайте главный вопрос: вы делаете код понятнее или просто короче?

Источник: Matt Smith — I stopped destructuring everything