Булевы значения, null и undefined

Булев тип до смешного мал: всего два значения, true («да») и false («нет»), – и при этом на нём держится вся логика программ. Чаще всего булевы значения не пишут руками, а получают из сравнений: 5 > 3 – это true. Методы из урока о строках тоже отвечают да/нет: 'кот'.includes('о')true. Подробный разбор – в уроке «Операторы сравнения».

Тип из двух значений

true и false – топливо для будущих условий.

compare.jsjs
console.log(5 > 3);  // trueconsole.log(2 > 7);  // false// true – методы тоже отвечают да/нетconsole.log('кот'.includes('о'));// результат сравнения можно сохранитьconst isAdult = 20 > 17;console.log(isAdult);  // true
Сравнение – это выражение: его результат можно сохранить в переменную и вывести.

true и false пишутся без кавычек. В кавычках 'true' и 'false' становятся обычными строками – текстом из четырёх и пяти букв, к логике отношения не имеющим.

bool-quotes.jsjs
// boolean – без кавычекconst ready = false;// string – обычная строка из пяти буквconst text = 'false';

Имя булевой переменной – это вопрос

Булево значение – это ответ «да» или «нет». Но ответ бесполезен, пока неизвестен вопрос, а вопрос в коде задаёт имя переменной. Поэтому булевы переменные называют так, чтобы имя читалось вопросом: isAdult – «совершеннолетний?», hasAccess – «есть доступ?», canEdit – «может редактировать?». Тогда строка const isAdult = true читается целиком: «совершеннолетний? – да».

Отсюда и приставки: is – «является ли», has – «есть ли», can – «может ли», should – «нужно ли». Это не требование языка: const adult = true движок примет так же охотно. Это договорённость между людьми, и держится она на том, что код читают куда чаще, чем пишут.

naming.jsjs
// имя-вопрос: значение читается как ответ// совершеннолетний? – даconst isAdult = true;// есть доступ? – нетconst hasAccess = false;// может редактировать? – даconst canEdit = true;// нужно ли повторить? – нетconst shouldRetry = false;
Четырёх приставок is, has, can и should достаточно для большинства первых задач. Позже вам могут встретиться и другие вопросительные имена.

Второе, что даёт имя-вопрос, – по нему виден тип. При объявлении переменной в JavaScript её тип отдельно не указывают: тип принадлежит текущему значению, поэтому имя помогает читателю понять, что ожидается внутри. Увидев hasAccess, читатель уверен: внутри true или false. Увидев access – не знает ничего: там может оказаться строка 'admin', число или объект.

naming-type.jsjs
// имя-вопрос: тип виден без чтения остального кода// точно true или falseconst hasAccess = false;// имя-существительное: что внутри – приходится гадать// булево? строка? уровень доступа числом?const access = 'admin';

И отдельно – про отрицание в имени. isNotReady выглядит безобидно, пока не дойдёт до чтения: «не готов? – нет» – на такой фразе спотыкаешься даже в своём коде, а в чужом тем более. Задавайте вопрос в положительной форме: isReady.

naming-negation.jsjs
// «не готов? – нет»: так это готов или нет?const isNotReady = false;// «готов? – да»: читается сразуconst isReady = true;
Один и тот же факт, но положительный вопрос не заставляет разворачивать двойное отрицание.

Как называть булевы переменные

  • Имя-вопрос с приставкой is, has, can, shouldisAdult, hasAccess
  • Существительное: признак это или сама сущность – не разобратьadult, access
  • Отрицание в имени: ответ придётся читать двойным отрицаниемisNotReady
  • Имя ни о чём: вопрос по нему не восстановитьflag, status, check
  • Язык примет любое имя – приставки нужны читателю, а не движку

Два вида пустоты

null – пусто нарочно; undefined – ещё не заполнено.

null обычно используют как явную метку: значение намеренно отсутствует, сброшено или пока не найдено. Например, let winner = null – победитель пока не определён, и это осмысленное состояние игры. Готовые функции тоже отвечают null: поиск, который ничего не нашёл, возвращает именно его.

undefined обычно появляется, когда значение ещё не было задано: переменную объявили без начального значения или спросили у объекта несуществующее свойство (с объектами познакомимся в уроке «Массив и объект: первое знакомство»). Встретили его в выводе – чаще всего это сигнал: «что-то забыли заполнить».

empty.jsjs
// пусто по задумке: победителя пока нетlet winner = null;console.log(winner);  // null// объявили, но ничего не положилиlet score;// undefined – появился самconsole.log(score);

undefined не присваивают руками

Записать undefined в переменную самому язык не мешает: let cart = undefined – рабочая строка. Но так обычно не пишут, и причина не в стиле. Пока undefined появляется только сам по себе, смысл у него надёжный: «значение сюда ещё не задавали».

Присвоив undefined руками, вы это различие стираете. Теперь undefined в переменной значит либо «значение не задавали», либо «программист намеренно очистил» – и по самому значению эти случаи уже не разделить. А для намеренной пустоты есть null.

По принятой договорённости намеренное отсутствие чаще обозначают null, а undefined обычно оставляют языку и API. Это не запрет языка, а способ сохранить понятный смысл.

manual-null.jsjs
// пусто намеренно – решение человекаlet winner = null;// а это пустота языка: значение не задавалиlet score;console.log(winner);console.log(score);
Консоль
null
undefined
По выводу видно, где решение человека, а где пустота языка.
manual-undefined.jsjs
// undefined записали рукамиlet cart = undefined;// а сюда он попал самlet score;console.log(cart);console.log(score);
Консоль
undefined
undefined
Обе строки напечатали одно и то же: «очистили» и «забыли» уже не различить.

// теперь вы знаете

  1. boolean – два значения: true и false, ответы на да/нет-вопросы
  2. Имя булевой переменной – вопрос: isAdult, hasAccess, canEdit
  3. null – отсутствие задано намеренно, undefined – значение ещё не определено
  4. Намеренное отсутствие чаще обозначают null; undefined обычно оставляют языку и API
  5. Сравнения и логика возвращают именно boolean
  6. typeof null – 'object': историческая особенность, а не объект

Проверьте себя

Что выведет console.log(10 > 100)?

Какой тип у значения 'false'?

Что вернёт typeof null?

Что выведет код: let city; console.log(city)?

переключают уроки · не работают при фокусе в полях ввода