Выразительный JavaScript - страница 7
>false
, второе.Неопределённые значения
Существуют два специальных значения, >null
и >undefined
, которые используются для обозначения отсутствия осмысленного значения. Сами по себе они никакой информации не несут.
Много операторов, которые не выдают значения, возвращают >undefined
просто для того, чтобы что-то вернуть. Разница между >undefined
и >null
появилась в языке случайно, и обычно не имеет значения.
Автоматическое преобразование типов
Ранее я упоминал, что JavaScript позволяет выполнять любые, подчас очень странные программы. К примеру:
>console.log(8 * null)
>// → 0
>console.log("5" - 1)
>// → 4
>console.log("5" + 1)
>// → 51
>console.log("пять" * 2)
>// → NaN
>console.log(false == 0)
>// → true
Когда оператор применяется «не к тому» типу величин, JavaScript втихую преобразовывает величину к нужному типу, используя набор правил, которые не всегда соответствуют вашим ожиданиям. Это называется приведением типов (coercion). В первом выражении >null
превращается в >0
, а >“5”
становится >5
(из строки – в число). Однако в третьем выражении >+
выполняет конкатенацию (объединение) строк, из-за чего >1
преобразовывается в >“1”
(из числа в строку).
Когда что-то неочевидное превращается в число (к примеру, >“пять”
или >undefined
), возвращается значение >NaN
. Последующие арифметические операции с >NaN
опять получают >NaN
. Если вы получили такое значение, поищите, где произошло случайное преобразование типов.
При сравнении величин одного типа через >==
, легко предсказать, что вы должны получить true, если они одинаковые (исключая случай с >NaN
). Но когда типы различаются, JavaScript использует сложный и запутанный набор правил для сравнений. Обычно он пытается преобразовать тип одной из величин в тип другой. Когда с одной из сторон оператора возникает >null
или >undefined
, он выдаёт >true
только если обе стороны имеют значение >null
или >undefined
.
>console.log(null == undefined);
>// → true
>console.log(null == 0);
>// → false
Последний пример демонстрирует полезный приём. Когда вам надо проверить, имеет ли величина реальное значение вместо >null
или >undefined
, вы просто сравниваете её с >null
при помощи >==
или >!=
.
Но что, если вам надо сравнить нечто с точной величиной? Правила преобразования типов в булевские значения говорят, что >0
, >NaN
и пустая строка >“”
считаются >false
, а все остальные – >true
. Поэтому >0 == false
и >“” == false
. В случаях, когда вам не нужно автоматическое преобразование типов, можно использовать ещё два оператора: >===
и >!==
. Первый проверяет, что две величины абсолютно идентичны, второй – наоборот. И тогда сравнение >“” === false
возвращает >false
.
Рекомендую использовать трёхсимвольные операторы сравнения для защиты от неожиданных преобразований типов, которые могут привести к непредсказуемым последствиям. Если вы уверены, что типы сравниваемых величин будут совпадать, можно спокойно использовать короткие операторы.
Короткое вычисление логических операторов
Логические операторы >&&
и >||
работают с величинами разных типов очень странным образом. Они преобразуют величину с левой стороны оператора в булевскую, чтобы понять, что делать дальше, но в зависимости от оператора и от результата этого преобразования, возвращают оригинальное значение либо левой, либо правой части.
К примеру, >||
вернёт значение с левой части, когда его можно преобразовать в >true
– а иначе вернёт правую часть.
>console.log(null || "user")
>// → user
>console.log("Karl" || "user")
>// → Karl
Такая работа оператора >||
позволяет использовать его как откат к значению по умолчанию. Если вы дадите ему выражение, которое может вернуть пустое значение слева, то значение справа будет служить заменой на этот случай.
Оператор >&&
работает сходным образом, но наоборот. Если величина слева преобразовывается в >false
, он возвращает эту величину, а иначе – величину справа.
Ещё одно важное их свойство – выражение в правой части вычисляется только при необходимости. В случае >true || X
не важно, чему равно >X
. Даже если это какое-то ужасное выражение. Результат всегда >true
и >X
не вычисляется. Так же работает