Урок по треку JavaScript 8 мин

Современный синтаксис за 8 минут

Деструктуризация, spread, ?. и ??, Map и Set, новинки ES2022-ES2025.

С 2015 года JavaScript обновляется каждый год. На собесе ждут, что вы свободно читаете современный код и знаете, какие задачи решают новые возможности. Здесь всё, что поддерживается во всех актуальных браузерах и в Node.js 22.

Деструктуризация

const { name, age = 18, address: { city } = {} } = user;
const [first, , third, ...rest] = list;
[a, b] = [b, a]; // обмен значений без временной переменной
  • Значение по умолчанию срабатывает только для undefined, не для null.
  • Переименование: const { name: userName } = user.
  • Деструктуризация null или undefined бросает TypeError: const { a } = null.
  • В параметрах: function f({ id, title } = {}) {}.

Spread и rest

Три точки означают разное в зависимости от места:

  • spread раскрывает: [...arr, 4], { ...obj, a: 1 }, fn(...args);
  • rest собирает: function f(...args), const { a, ...others } = obj.

При spread объектов поздние свойства перезаписывают ранние: { ...defaults, ...options }. Копируются только собственные перечисляемые свойства, геттеры вычисляются и превращаются в значения.

Опциональная цепочка и нулевое слияние

user?.address?.city      // undefined, если чего-то нет, без TypeError
user.getName?.()         // вызов, только если метод существует
list?.[0]                // доступ по индексу
const port = config.port ?? 3000;

?. останавливается при null или undefined и возвращает undefined для всего выражения (короткое замыкание: остаток цепочки не вычисляется).

?? подставляет правую часть только для null и undefined, а || для любого ложного значения. Для чисел и строк, где 0 и '' допустимы, нужен ??. Смешивать ?? с || или && без скобок запрещено синтаксисом.

Логическое присваивание (ES2021)

options.timeout ??= 5000; // присвоить, если null или undefined
cache[key] ||= compute(); // присвоить, если ложно
user.isAdmin &&= check(); // присвоить, если истинно

Присваивание происходит только если нужно: a ||= b не трогает a, если оно истинно, и b при этом не вычисляется.

Шаблонные строки

`Привет, ${name}` поддерживают многострочность и выражения. Теговые шаблоны tag`...` передают строки и значения в функцию: так устроены styled-components, graphql, sql-хелперы.

Map, Set, WeakMap, WeakSet

  • Map: ключи любого типа, порядок вставки, size, быстрые частые добавления и удаления. Объект для этого хуже: ключи только строки и символы, есть унаследованные свойства.
  • Set: уникальные значения. Убрать дубли: [...new Set(arr)].
  • WeakMap / WeakSet: ключи только объекты (и незарегистрированные символы), не мешают сборке мусора, не итерируются.

Новые методы Set (ES2025, есть в Node 22 и всех браузерах с 2024 года): union, intersection, difference, symmetricDifference, isSubsetOf, isSupersetOf, isDisjointFrom.

Symbol

Уникальный примитив: Symbol('id') !== Symbol('id'). Используется для ключей, которые не пересекутся с чужими, и для встроенных протоколов: Symbol.iterator, Symbol.toPrimitive, Symbol.asyncIterator. Символьные ключи не видны в Object.keys, for...in и JSON.stringify.

Новые методы массивов и объектов

ВерсияЧто
ES2019flat, flatMap, Object.fromEntries
ES2020?., ??, BigInt, Promise.allSettled, globalThis
ES2021??=, `
ES2022at(), Object.hasOwn, поля и #-члены классов, top-level await, Error.cause
ES2023findLast, findLastIndex, toSorted, toReversed, toSpliced, with
ES2024Object.groupBy, Map.groupBy, Promise.withResolvers, Array.fromAsync
ES2025методы Set, iterator helpers, RegExp модификаторы

Самое полезное на практике:

arr.at(-1);                         // последний элемент
const sorted = arr.toSorted((a, b) => a - b); // без мутации
const updated = arr.with(0, 'новое');         // замена по индексу без мутации
const byRole = Object.groupBy(users, (u) => u.role); // { admin: [...], user: [...] }
const { promise, resolve, reject } = Promise.withResolvers();

Object.groupBy возвращает объект без прототипа, у него нет hasOwnProperty. Map.groupBy возвращает Map и подходит, когда ключи объекты.

Частые ошибки

  • || вместо ?? для значений, где 0 допустим.
  • Ждать, что дефолт в деструктуризации сработает для null.
  • Думать, что spread делает глубокую копию.
  • ?. в левой части присваивания: a?.b = 1 это SyntaxError.

Что спросят на собесе

  • Чем ?? отличается от ||, как работает ?..
  • Что такое деструктуризация, когда срабатывает значение по умолчанию.
  • Чем Map отличается от объекта, Set от массива, WeakMap от Map.
  • Какие новые возможности ES2022-ES2024 вы используете.
  • Чем spread отличается от rest.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.