Приведение типов и операторы
Приведение типов и к булеву, нестрогое против строгого равенства и семейства операторов — логические, побитовые, унарные.
13 вопросов
MiddleТеорияОчень частоВ чём разница между == и ===?
В чём разница между == и ===?
=== (строгое) сравнивает значение и тип без преобразования, поэтому разные типы никогда не равны. == (нестрогое) сначала приводит операнды к общему типу, поэтому 0 == '', 1 == '1' и null == undefined равны true. NaN не равен ничему, а +0 === -0 даёт true.
Типичные ошибки
- ✗Считать, что
===выполняет приведение — он никогда не преобразует типы - ✗Думать, что
NaN === NaNэтоtrue - ✗Полагать, что
==сравнивает содержимое объектов, а не ссылку
Уточняющие вопросы
- →Разберите, как
==приводит обе стороны в[] == ![]. - →Почему
+0 === -0это true, аObject.is(+0, -0)это false?
MiddleТеорияОчень частоКакое значение возвращают &&, || и ?? и как они короткозамкнуты?
Какое значение возвращают &&, || и ?? и как они короткозамкнуты?
Эти операторы короткозамкнуты и возвращают один из операндов, а не приведённое булево. && возвращает первый ложный операнд или последний, если все истинные. || возвращает первый истинный операнд, иначе последний. ?? возвращает правую часть, только когда левая null или undefined, игнорируя прочие ложные значения. Поэтому 0 || 'x' это 'x', а 0 ?? 'x' это 0.
Типичные ошибки
- ✗Считать, что операторы возвращают булево, а не один из операндов
- ✗Путать
??с||, забывая, что он проверяет лишьnull/undefined - ✗Думать, что обе стороны всегда вычисляются, упуская пропуск при замыкании
Уточняющие вопросы
- →Что возвращает
'' && 'x'и почему замыкание останавливается раньше? - →Когда
??и||дадут разный результат для одного левого операнда?
JuniorТеорияЧастоЧто такое неявное приведение типов в JavaScript?
Что такое неявное приведение типов в JavaScript?
Неявное приведение — это автоматическое преобразование операнда к другому типу для выполнения операции. + со строкой приводит другую сторону к строке (1 + '2' это '12'); прочая арифметика и сравнения приводят к числу ('3' * 2 это 6). В булевом контексте значение приводится к truthy или falsy.
Типичные ошибки
- ✗Считать, что
+всегда численный — со строковым операндом он конкатенирует - ✗Думать, что
===выполняет приведение (он никогда этого не делает) - ✗Ожидать, что приведение выбросит ошибку при несовпадении типов, а не молча преобразует
Уточняющие вопросы
- →Почему
1 + '2'даёт'12', а'3' * 2даёт6? - →В чём разница между
Number(x)и унарным+x?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
3.5 -1 3
Открыть задачу →Типичные ошибки
- ✗Ждать
3для7 / 2: в JavaScript один типnumberи для целых, и для дробных чисел, поэтому/сохраняет дробную часть и даёт3.5. - ✗Считать остаток неотрицательным, как в математике: в JavaScript знак остатка совпадает со знаком делимого, поэтому
-7 % 3— это-1.
Уточняющие вопросы
- →Что выведет
Math.trunc(-7 / 2)и чем это отличается отMath.floor(-7 / 2)? - →Как получить остаток, который не бывает отрицательным, для
-7и3?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
true true false
Открыть задачу →Типичные ошибки
- ✗Ждать
falseдля0 == "":==сначала приводит обе стороны к одному типу, пустая строка превращается в число0, и стороны оказываются равны. - ✗Ждать
trueдляnull === undefined:===никогда не приводит типы, аnullиundefined— разные типы, поэтому результатfalse.
Уточняющие вопросы
- →Что выведет
0 === ""и почему не то же, что0 == ""? - →Что выведет
null == 0, еслиnull == undefinedдаётtrue?
JuniorТеорияЧастоЧто выведет программа?
Что выведет программа?
53 2 10
Открыть задачу →Типичные ошибки
- ✗Ждать
8для"5" + 3: если одна из сторон+— строка,+склеивает строки, а не складывает числа, поэтому3становится"3", и выходит"53". - ✗Ждать
NaNот-или*со строками: эти операторы работают только с числами, поэтому сначала превращают"5"и"2"в5и2.
Уточняющие вопросы
- →Что выведет
"5" - "x"и почему? - →Как сделать, чтобы
"5" + 3вывело8?
JuniorТеорияЧастоКакие значения в JavaScript ложные и что делает !!x?
Какие значения в JavaScript ложные и что делает !!x?
Восемь ложных значений: false, 0, -0, 0n, "", null, undefined и NaN; остальные истинны, даже "0" и []. !!x применяет ! дважды и даёт true или false, как Boolean(x).
Типичные ошибки
- ✗Считать
"0"или[]ложными: ложны только восемь перечисленных значений, поэтому непустая строка вроде"0"и любой массив, даже пустой, истинны. - ✗Ждать, что
!!xвернётx: первый!превращаетxвtrueилиfalseи переворачивает, второй переворачивает обратно, так что результат всегдаboolean.
Уточняющие вопросы
- →Выполнит ли
if ("0")своё тело и почему? - →Чем
!!xотличается отBoolean(x)?
JuniorТеорияИногдаКакие основные категории операторов есть в JavaScript?
Какие основные категории операторов есть в JavaScript?
Операторы JavaScript группируют по назначению: арифметические (+ - * / % **), сравнения (< > == ===), логические (&& || ! ??), битовые (& | ^ ~ << >>), присваивания (= += &&=), тернарный ?: и оператор запятая. Они различаются и по арности: большинство бинарные, но ! и typeof унарные, а ?: тернарный.
Типичные ошибки
- ✗Думать, что
?:— лишь синтаксис дляif, а не оператор, дающий значение - ✗Считать, что логические операторы всегда возвращают булево, а не один из операндов
- ✗Полагать, что в JavaScript нет битовых операторов, ведь числа — с плавающей точкой
Уточняющие вопросы
- →Какова арность
?:и почему это важно? - →К какой категории относится
??и чем он отличается от||?
JuniorТеорияИногдаКакие унарные операторы есть в JavaScript и что делает каждый?
Какие унарные операторы есть в JavaScript и что делает каждый?
Унарный оператор берёт один операнд. typeof x возвращает строку типа, например number. delete obj.k удаляет собственное свойство. void expr вычисляет expr и возвращает undefined. !x приводит к булеву и инвертирует его. Унарный +x преобразует в число (+'5' это 5), а унарный -x отрицает численно. ++/-- увеличивают или уменьшают на месте.
Типичные ошибки
- ✗Думать, что
deleteосвобождает переменную или память, а не удаляет собственное свойство - ✗Ожидать, что
voidвозвращаетnull, а не всегдаundefined - ✗Забывать, что унарные
+/-приводят к числу, поэтому+'5'это5, а не'5'
Уточняющие вопросы
- →Что возвращает
deleteпри попытке удалить неконфигурируемое свойство? - →Почему
void 0иногда используют как безопасный способ получитьundefined?
MiddleТеорияИногдаКак работают тернарный ?: и оператор запятая в JavaScript?
Как работают тернарный ?: и оператор запятая в JavaScript?
Тернарный cond ? a : b — единственный оператор с тремя операндами: он вычисляет cond, затем возвращает a, если истинно, иначе b, и это выражение, дающее значение. Оператор запятая a, b, c вычисляет каждый операнд слева направо, но возвращает только значение последнего, поэтому (1, 2, 3) это 3. Промежуточные операнды выполняются ради побочных эффектов.
Типичные ошибки
- ✗Думать, что
?:— инструкция, а не выражение, возвращающее значение - ✗Считать, что оператор запятая возвращает первый операнд, а не последний
- ✗Забывать, что тернарный вычисляет только выбранную ветку
Уточняющие вопросы
- →Как оператор запятая позволяет циклу
forобновлять две переменные сразу? - →Почему тернарные можно вкладывать и когда это вредит читаемости?
SeniorТеорияИногдаКак нестрогое равенство приводит операнды? Разберите [] == ![].
Как нестрогое равенство приводит операнды? Разберите [] == ![].
== следует шагам абстрактного равенства: null == undefined — особый случай, всегда true; сравнение число-строка приводит строку к числу; булев операнд сначала приводится к числу; сравнение объект-примитив приводит объект через ToPrimitive. Для [] == ![]: ![] это false, затем 0; [] становится '', затем 0; поэтому 0 == 0 это true.
Типичные ошибки
- ✗Сравнивать истинность сторон напрямую вместо того, чтобы идти по шагам приведения
- ✗Забывать, что булев операнд приводится к числу перед сравнением
- ✗Считать, что объект сравнивается по своему JSON, а не через
ToPrimitive
Уточняющие вопросы
- →Почему
[] == ''выполняется, а[] === ''— нет? - →Как
ToPrimitiveвыбирает междуvalueOfиtoStringобъекта?
SeniorТеорияИногдаКак приоритет и ассоциативность операторов определяют порядок вычисления в JavaScript?
Как приоритет и ассоциативность операторов определяют порядок вычисления в JavaScript?
Приоритет решает, какой оператор связывает сильнее без скобок, поэтому * выполняется раньше + в 1 + 2 * 3. Ассоциативность разрешает ничью между операторами равного приоритета: большинство левоассоциативны, но =, ** и ?: правоассоциативны. Приоритет управляет лишь группировкой, а не порядком вычисления операндов слева направо. Частые ловушки — ** сильнее унарного - и && сильнее ||.
Типичные ошибки
- ✗Путать приоритет (группировку) с порядком вычисления операндов (он слева направо)
- ✗Считать
=,**и?:левоассоциативными, как большинство операторов - ✗Забывать, что
&&сильнее||, что меняет группировку условий
Уточняющие вопросы
- →Почему
-2 ** 2— синтаксическая ошибка и как записать это правильно? - →Как правоассоциативность заставляет
a = b = cприсваивать справа?
MiddleТеорияРедкоКакие битовые операторы есть в JavaScript и что делает приём ~~?
Какие битовые операторы есть в JavaScript и что делает приём ~~?
Битовые операторы: & (И), | (ИЛИ), ^ (XOR), ~ (НЕ), << (сдвиг влево), >> (сдвиг вправо с сохранением знака) и >>> (сдвиг вправо с заполнением нулями). Они сначала приводят операнды к 32-битным знаковым целым, отбрасывая дробную часть. Поэтому двойное ~~x усекает к нулю как Math.trunc, например ~~4.9 это 4, а ~~-4.9 это -4.
Типичные ошибки
- ✗Забывать, что битовые операторы сначала приводят операнды к 32-битным знаковым целым
- ✗Путать
~~x(усечение) с округлением какMath.round - ✗Считать
>>и>>>одинаковыми, игнорируя обработку знака
Уточняющие вопросы
- →Почему
~~xневерно усекает числа больше 2³¹−1? - →Чем
>>>отличается от>>, когда операнд отрицательный?