Система типов
Примитивные типы, typeof, null против undefined, NaN, значение против ссылки, объекты-обёртки и неизменяемость.
8 вопросов
JuniorТеорияОчень частоВ чём разница между null и undefined?
В чём разница между null и undefined?
undefined — переменная объявлена, но не присвоена (значение по умолчанию); null — явно присваиваемое «нет значения». typeof undefined — undefined, а typeof null — object. Численно null равен 0, а undefined — NaN. Они равны нестрого (==), но не строго (===).
Типичные ошибки
- ✗Думать, что
null === undefined— этоtrue(выполняется лишь==) - ✗Ожидать, что
typeof null— этоnull, а неobject - ✗Считать, что оба приводятся к одному числу —
nullэто0, аundefinedэтоNaN
Уточняющие вопросы
- →Почему
null == undefinedвыполняется, аnull == 0— нет? - →Когда стоит намеренно присвоить
nullвместо того, чтобы оставить значениеundefined?
JuniorТеорияЧастоСколько примитивных типов в JavaScript и что делает значение примитивом?
Сколько примитивных типов в JavaScript и что делает значение примитивом?
В JavaScript 7 примитивных типов: string, number, boolean, null, undefined, bigint и symbol. Примитив — это неизменяемое значение, сравниваемое по значению, без собственных свойств и методов; всё остальное — объект.
Типичные ошибки
- ✗Считать
object, массивы или функции примитивными типами - ✗Забывать
bigintиsymbol, перечисляя только исходные пять - ✗Полагать, что
nullне примитив, разtypeof null— этоobject
Уточняющие вопросы
- →Почему
typeof nullвозвращаетobject, а неnull? - →Как примитив вроде строки предоставляет методы вроде
toUpperCase, если их у него нет?
JuniorТеорияЧастоЧто возвращает оператор typeof для значений разного вида?
Что возвращает оператор typeof для значений разного вида?
typeof возвращает строку с типом: string, number, boolean, undefined, bigint, symbol, function для вызываемых и object для объектов, массивов и null. Результат object для null — давняя ошибка языка.
Типичные ошибки
- ✗Ожидать, что
typeof null— этоnull, а неobject - ✗Ожидать, что
typeof []— этоarray; на делеobject(используйтеArray.isArray) - ✗Думать, что
typeofна необъявленной переменной выбрасывает ошибку — он безопасно возвращаетundefined
Уточняющие вопросы
- →Как надёжно отличить массив от обычного объекта?
- →Почему
typeofбезопасен для необъявленного идентификатора, хотя его чтение напрямую выбрасывает ошибку?
MiddleТеорияЧастоЧем отличаются примитивы и объекты при присваивании или передаче в функцию?
Чем отличаются примитивы и объекты при присваивании или передаче в функцию?
Примитивы копируются по значению: присваивание или передача дублирует значение, поэтому изменения копии не влияют на оригинал. Объекты копируют ссылку на тот же объект, поэтому его изменение через любую привязку видно обеим. JavaScript всегда передаёт по значению — но для объектов это значение является ссылкой (передача по разделению).
Типичные ошибки
- ✗Считать, что переприсваивание параметра-объекта меняет объект вызывающего
- ✗Думать, что присваивание объекта делает глубокую копию, а не разделяет ссылку
- ✗Говорить, что JavaScript передаёт объекты по ссылке (он передаёт по значению ссылку)
Уточняющие вопросы
- →Почему мутация параметра-объекта влияет на вызывающего, а его переприсваивание — нет?
- →Как сделать независимую копию объекта или массива?
MiddleТеорияИногдаИзменяемы ли значения в JavaScript и что на самом деле защищает const?
Изменяемы ли значения в JavaScript и что на самом деле защищает const?
Примитивы неизменяемы — нельзя изменить значение вроде 5 или 'hi', можно лишь перепривязать переменную к новому. Объекты и массивы изменяемы: их содержимое можно менять на месте. const запрещает лишь перепривязку переменной, а не мутацию — у const-объекта можно менять свойства; для поверхностной неизменяемости используйте Object.freeze.
Типичные ошибки
- ✗Думать, что
constделает содержимое объекта неизменяемым - ✗Считать, что методы строк меняют исходную строку на месте
- ✗Полагать, что
Object.freezeглубокий — он замораживает лишь верхний уровень
Уточняющие вопросы
- →Как сделать вложенный объект глубоко неизменяемым?
- →Почему
const arr = []; arr.push(1)срабатывает, аarr = [1]выбрасывает ошибку?
MiddleТеорияИногдаЧто такое NaN и как надёжно проверить, что значение равно NaN?
Что такое NaN и как надёжно проверить, что значение равно NaN?
NaN (Not-a-Number) — числовое значение для неопределённого результата вычислений, например 0/0 или Number('x'); typeof NaN это number. Это единственное значение, не равное самому себе, поэтому NaN === NaN это false. Проверяйте через Number.isNaN(x), который не приводит тип, в отличие от глобального isNaN, приводящего аргумент к числу.
Типичные ошибки
- ✗Проверять через
x === NaN, что всегда даётfalse - ✗Считать, что
isNaNиNumber.isNaNведут себя одинаково — приводит лишь глобальный - ✗Ожидать, что
typeof NaN— это что-то иное, чемnumber
Уточняющие вопросы
- →Почему
isNaN('hello')возвращаетtrue, аNumber.isNaN('hello')—false? - →Как проверить значение на
NaNбез всякой встроенной функции?
MiddleТеорияИногдаКак примитив вроде строки предоставляет методы, если у примитива их нет?
Как примитив вроде строки предоставляет методы, если у примитива их нет?
Когда вы обращаетесь к свойству или методу примитива ('hi'.toUpperCase()), движок временно оборачивает его в соответствующий объект-обёртку — String, Number, Boolean, Symbol или BigInt, — выполняет метод и отбрасывает обёртку. У null и undefined обёртки нет, поэтому доступ к их свойствам выбрасывает TypeError.
Типичные ошибки
- ✗Думать, что примитивы хранят свои методы, а не заимствуют их у обёртки
- ✗Считать, что временная обёртка сохраняется и меняет тип значения
- ✗Ожидать, что
nullилиundefinedоборачиваются — доступ к их свойствам выбрасывает ошибку
Уточняющие вопросы
- →Почему присваивание свойства примитиву (
s.foo = 1) молча проваливается? - →В чём разница между
'hi'иnew String('hi')?
SeniorТеорияИногдаКак === сравнивает объекты и чем отличается от него Object.is?
Как === сравнивает объекты и чем отличается от него Object.is?
=== для объектов сравнивает идентичность, а не содержимое — два разных объекта никогда не равны, даже с одинаковыми свойствами; равны лишь две ссылки на один объект. Object.is совпадает с ===, кроме двух случаев: Object.is(NaN, NaN) это true, а Object.is(+0, -0) это false. Array.prototype.includes использует близкий SameValueZero, тоже считающий NaN равным.
Типичные ошибки
- ✗Ожидать, что два объекта с одинаковым содержимым
===(равны лишь по одной ссылке) - ✗Думать, что
Object.isведёт себя как===дляNaNи знаковых нулей - ✗Полагать, что
===глубоко сравнивает свойства объектов
Уточняющие вопросы
- →Как сравнить два объекта по значению (структурное равенство)?
- →Почему
[NaN].includes(NaN)возвращаетtrue, а[NaN].indexOf(NaN)возвращает-1?