Возможности ES6+
Классы, модули, шаблонные литералы, деструктуризация, spread/rest, параметры по умолчанию, динамические импорты, опциональная цепочка и оператор нулевого слияния.
13 вопросов
JuniorТеорияОчень частоЧто такое деструктурирующее присваивание и как с его помощью поменять местами две переменные?
Что такое деструктурирующее присваивание и как с его помощью поменять местами две переменные?
Деструктуризация распаковывает значения из массивов или свойства из объектов в отдельные переменные одним выражением. Массивная форма [a, b] = arr связывает по позиции; объектная {x, y} = obj — по совпадению имени свойства. Чтобы поменять две переменные местами, пишут [a, b] = [b, a]: правая часть строит временный массив, затем его элементы присваиваются обратно, так что отдельная временная переменная не нужна.
Типичные ошибки
- ✗Думать, что массивная деструктуризация связывает по имени, а не по позиции
- ✗Считать, что обмен
[a, b] = [b, a]всё равно требует временной переменной - ✗Полагать, что деструктуризация изменяет или удаляет ключи из источника
Уточняющие вопросы
- →Как объектная деструктуризация решает, в какую переменную попадёт каждое значение?
- →Какое значение получит деструктурированная переменная, если ячейки источника нет?
JuniorТеорияОчень частоЧто делает оператор расширения ... в литералах массива, литералах объекта и аргументах вызова?
Что делает оператор расширения ... в литералах массива, литералах объекта и аргументах вызова?
Расширение ... раскрывает содержимое итерируемого объекта или объекта на месте. В литерале массива [...iterable] оно раскладывает каждый элемент, так что [...'ab'] даёт ['a', 'b']; в вызове f(...arr) передаёт каждый элемент отдельным аргументом; в литерале объекта {...obj} копирует собственные перечислимые свойства (поверхностная копия). Оно читает из источника — в отличие от rest ..., который собирает несколько элементов в один.
Типичные ошибки
- ✗Путать spread (раскрывает один во многие) с rest (собирает многие в один)
- ✗Считать, что
{...obj}делает глубокий клон, а не поверхностную копию - ✗Думать, что spread работает только с массивами, а не строками и прочими итерируемыми
Уточняющие вопросы
- →В чём разница между синтаксисом расширения
...и rest...? - →
{...obj}— это поверхностная или глубокая копия объекта?
JuniorТеорияЧастоКак объявить class в ES6 и как создать экземпляр на его основе?
Как объявить class в ES6 и как создать экземпляр на его основе?
Используйте ключевое слово class с именем, необязательным constructor для настройки каждого экземпляра и определениями методов прямо в теле (без запятых и слова function). constructor выполняется при вызове new ClassName(args), который создаёт новый объект, привязывает его к this и возвращает. Методы из тела общие, а не копируются в каждый экземпляр.
Типичные ошибки
- ✗Разделять члены класса запятыми как в литерале объекта — в теле класса запятых нет
- ✗Вызывать
classбезnew, что выбрасываетTypeError - ✗Думать, что методы тела копируются в каждый экземпляр, а не общие
Уточняющие вопросы
- →Что произойдёт, если вызвать конструктор
classбез ключевого словаnew? - →Где на самом деле находятся методы, написанные в теле класса?
JuniorТеорияЧастоЧто такое значения параметров функции по умолчанию в ES6 и когда они реально применяются?
Что такое значения параметров функции по умолчанию в ES6 и когда они реально применяются?
Параметры по умолчанию позволяют писать function f(x = 10), чтобы параметр получал запасное значение при отсутствии аргумента. По умолчанию срабатывает только когда аргумент равен undefined — либо вовсе опущен, либо явно передан как undefined. Другие ложные значения вроде 0, '', null или false — настоящие аргументы и подавляют умолчание. Выражение по умолчанию вычисляется лениво, один раз за вызов и только при необходимости.
Типичные ошибки
- ✗Думать, что любой ложный аргумент вроде
0или''запускает умолчание — толькоundefined - ✗Считать, что явный аргумент
undefinedобходит умолчание - ✗Полагать, что выражение по умолчанию вычисляется раз при определении, а не на каждый вызов
Уточняющие вопросы
- →Запускает ли передача
nullпараметру с умолчанием его значение по умолчанию? - →Может ли поздний параметр по умолчанию ссылаться на значение более раннего параметра?
JuniorТеорияЧастоКак работают import и export в ES-модулях и какую область видимости имеют привязки модуля?
Как работают import и export в ES-модулях и какую область видимости имеют привязки модуля?
ES-модуль раскрывает привязки через export (именованные или один default) и подключает их в другом месте через import. Всё, что не экспортировано, остаётся приватным для файла — область видимости модуля это верхний уровень, а не глобальная, поэтому объявления верхнего уровня не становятся глобальными переменными. Каждый модуль выполняется один раз, имеет свою область видимости и всегда автоматически в строгом режиме, без директивы 'use strict'.
Типичные ошибки
- ✗Думать, что объявления верхнего уровня модуля становятся глобальными переменными
- ✗Считать, что модуль выполняется заново на каждый
import, а не один раз - ✗Забывать, что модули всегда автоматически в строгом режиме
Уточняющие вопросы
- →В чём разница между экспортом
defaultи именованнымexport? - →Сколько раз выполняется код верхнего уровня модуля, если его импортируют несколько файлов?
MiddleТеорияЧастоКак работают extends, super, static и приватные #fields в наследовании классов ES6?
Как работают extends, super, static и приватные #fields в наследовании классов ES6?
class B extends A делает B подклассом A. В конструкторе B нужно вызвать super(args) до использования this, что выполняет конструктор родителя; super.method() вызывает родительский метод. Члены static принадлежат самому классу, а не экземплярам, и наследуются подклассами. #field по-настоящему приватный — доступен только внутри тела объявляющего класса, невидим для подклассов и внешнего кода, и это не то же, что соглашение об именовании.
Типичные ошибки
- ✗Использовать
thisдо вызоваsuper()в конструкторе подкласса - ✗Думать, что члены
staticпринадлежат экземпляру или не наследуются подклассами - ✗Считать
#fieldсоглашением, которое подклассы или внешний код могут читать
Уточняющие вопросы
- →Почему
super()должен выполниться до обращения кthisв конструкторе подкласса? - →Может ли подкласс обратиться к
#private-полю родительского класса?
MiddleТеорияЧастоВ чём разница между циклами for...of и for...in в JavaScript?
В чём разница между циклами for...of и for...in в JavaScript?
for...of перебирает значения итерируемого объекта (Array, String, Map, Set и т.д.), так для ['a','b'] он даёт 'a', затем 'b'. for...in перебирает перечислимые строковые ключи свойств любого объекта, включая унаследованные и добавленные в массив, так для массива он даёт строки-индексы вроде '0', '1' плюс любые свои ключи. Используйте for...of для упорядоченных значений, for...in — для ключей объекта.
Типичные ошибки
- ✗Использовать
for...inна массиве, ожидая значения — он даёт строки-ключи - ✗Забывать, что
for...inобходит и унаследованные перечислимые свойства - ✗Считать, что
for...ofработает с любым обычным объектом, а не только итерируемым
Уточняющие вопросы
- →Почему
for...inпо массиву даёт строковые ключи, а не числа? - →Как перебрать пары обычного объекта с помощью
for...of?
MiddleТеорияЧастоЧто делает оператор нулевого слияния ?? и чем он отличается от ||?
Что делает оператор нулевого слияния ?? и чем он отличается от ||?
a ?? b возвращает a, если только a не равен null или undefined, и тогда возвращает b. Он отличается от ||, который возвращает правую часть при любом ложном левом операнде — включая 0, '', NaN и false. Так 0 ?? 5 даёт 0, а 0 || 5 даёт 5. Это делает ?? верным выбором для подстановки умолчания только при отсутствующих значениях, сохраняя законные ложные вроде 0 или ''.
Типичные ошибки
- ✗Считать
??и||взаимозаменяемыми, игнорируя реакцию||на0и'' - ✗Думать, что
??откатывается только наundefined, а не наnull - ✗Использовать
||для умолчания числа, ошибочно заменяя корректный0
Уточняющие вопросы
- →Чему равно
0 ?? 'x'по сравнению с0 || 'x'? - →Почему
??нужно брать в скобки при смешивании с&&или||?
MiddleТеорияЧастоЧто делает оператор опциональной цепочки ?., когда промежуточная ссылка равна nullish?
Что делает оператор опциональной цепочки ?., когда промежуточная ссылка равна nullish?
?. безопасно читает свойство, вызывает метод или индексирует: если значение слева равно null или undefined, всё выражение замыкается накоротко и даёт undefined, а не выбрасывает ошибку. Так a?.b.c возвращает undefined, когда a равен nullish, пропуская остаток цепочки. Формы: obj?.prop, obj?.[key] и fn?.(). Оно защищает только от nullish — прочие ложные значения доступны как обычно.
Типичные ошибки
- ✗Думать, что
?.замыкается на любом ложном значении, а не толькоnull/undefined - ✗Считать, что
?.защищает всю цепочку, а не только доступ перед собой - ✗Полагать, что при замыкании оно возвращает
null, а неundefined
Уточняющие вопросы
- →Как задать запасное значение кроме
undefinedпосле опциональной цепочки? - →Защищает ли
a?.b.cот nullish-значенияb, или толькоa?
MiddleТеорияИногдаЧто такое динамический import() и чем он отличается от статического оператора import?
Что такое динамический import() и чем он отличается от статического оператора import?
Динамический import('./mod') — функциеподобная форма, загружающая модуль во время выполнения и возвращающая промис, разрешающийся в объект пространства имён модуля. В отличие от статического import верхнего уровня, он может выполняться условно, внутри функций, со спецификатором, вычисленным в рантайме, и его await или цепляют через .then(). Сборщики используют его для разделения кода и ленивой загрузки, так что чанк подгружается только при реальной необходимости, а не заранее.
Типичные ошибки
- ✗Думать, что
import()возвращает модуль напрямую, а не промис - ✗Считать, что динамический импорт не может использовать вычисленный в рантайме спецификатор
- ✗Полагать, что он загружает всё заранее, упуская его цель разделения кода
Уточняющие вопросы
- →Как прочитать именованный экспорт из объекта, в который разрешается
import()? - →Почему динамический
import()включает разделение кода, которого нет у статическогоimport?
SeniorТеорияИногдаВ каком смысле классы ES6 — синтаксический сахар над прототипами, и чем они всё же отличаются?
В каком смысле классы ES6 — синтаксический сахар над прототипами, и чем они всё же отличаются?
class разворачивается в функцию-конструктор плюс настройку прототипа: методы из тела живут на Constructor.prototype и общие для экземпляров, точно как при ручном присваивании прототипу. Но классы не чистый сахар — их методы неперечислимы (поэтому не появляются в for...in), объявление class не всплывает пригодным образом (обращение к нему до объявления это ReferenceError, в отличие от функции), а всё тело всегда выполняется в строгом режиме.
Типичные ошибки
- ✗Думать, что методы класса — собственные перечислимые свойства, видимые в
for...in - ✗Считать, что объявление
classвсплывает и пригодно до своей строки - ✗Полагать, что классы — чистый сахар без отличий по строгому режиму и перечислимости
Уточняющие вопросы
- →Почему обращение к классу до его объявления выбрасывает ошибку, а не даёт
undefined? - →Как на практике убедиться, что метод класса неперечислим?
SeniorТеорияИногдаКак сочетаются вложенная деструктуризация, встроенные умолчания, rest, псевдонимы и параметры?
Как сочетаются вложенная деструктуризация, встроенные умолчания, rest, псевдонимы и параметры?
Деструктуризация компонуется рекурсивно: const {a: {b}} = obj добирается до вложенных объектов, псевдоним переименовывает через {x: y} (связывая y), а = value даёт умолчание, применяемое только когда ячейка undefined. Rest ...rest собирает оставшиеся элементы массива или свойства объекта в одну привязку (объектный rest должен быть последним). Можно деструктурировать прямо в списке параметров, напр. function f({x = 1, y} = {}), сочетая умолчания на уровне свойства и всего параметра.
Типичные ошибки
- ✗Думать, что
{x: y}связываетx, а неy— привязкой является имя справа - ✗Считать, что встроенные умолчания срабатывают на любом ложном значении, а не только
undefined - ✗Ставить объектный rest не последним в шаблоне
Уточняющие вопросы
- →Что произойдёт с
function f({x} = {})при вызовеf()без аргумента? - →Почему rest-элемент должен быть последним в шаблоне деструктуризации?
SeniorТеорияИногдаЧто такое живые привязки и статическая структура ESM, и чем ESM отличается от CommonJS?
Что такое живые привязки и статическая структура ESM, и чем ESM отличается от CommonJS?
Импорты ESM — живые привязки только для чтения: импортёр видит текущее значение экспортёра, поэтому обновлённая в модуле переменная отражается на стороне импорта, в отличие от CommonJS, который копирует значение в момент require. import/export ESM статичны — разрешаются до выполнения — что включает tree-shaking. Он также поддерживает await верхнего уровня. CommonJS (require/module.exports) динамичен, синхронен и копирует значения, загружаясь в момент вызова, а не разбираясь заранее.
Типичные ошибки
- ✗Думать, что импорты ESM копируют значения как CommonJS, а не являются живыми привязками
- ✗Считать, что
import/exportESM динамичен, а не статически анализируем - ✗Полагать, что импортированные привязки доступны для записи импортирующим модулем
Уточняющие вопросы
- →Почему статическая структура
import/exportвключает tree-shaking, аrequireнет? - →Чем копия значения CommonJS на практике отличается от живой привязки ESM?