Ранее я упоминал, что 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не вычисляется. Так же работает false && X– Xпросто игнорируется. Это называется коротким вычислением.
Оператор условия работает так же. Первое выражение всегда вычисляется, а из второго и третьего значения – только то, которое оказывается выбранным в результате.
Мы рассмотрели четыре типа величин JavaScript: числа, строки, булевские и неопределённые.
Эти величины получаются, когда мы пишем их имена ( true, null) или значения ( 13, “ёпрст”). Их можно комбинировать и изменять при помощи операторов. Для арифметики есть бинарные операторы ( +, -, *, /и %), объединение строк ( +), сравнение ( ==, !=, ===, !==, <, >, <=, >=) и логические операторы ( &&, ||), а также несколько унарных операторов ( -для отрицательного значения, !для логического отрицания и typeofдля определения типа величины).
Читать дальше