JavaScript 3. Преобразование типов данных
Числа и строки
В прошлой заметке мы разбирались с простыми типами данных в JavaScript. Сегодня мы немного разовьём эту тему, но снова не будем касаться объектов – сначала разберёмся с так сказать «примитивными» типами.
Прежде всего, вам следует запомнить, что JavaScript – язык с не жёсткой типизацией. Это означает, что многие переменные, в которых сохранены какие-то значения, можно трактовать по-разному. При этом, есть конструкции языка, которые сами справляются с подобным преобразованием и делают это неявно. Но обо всём по порядку.
Положим, я объявляю переменную и помещаю в неё число:
let a = 45.3;
Значение переменной «a» уже можно использовать в арифметических операциях. Скажем, можно продолжить скрипт так:
let b = 32 + a;
alert(b);
Что выведет в небольшом окошке функция alert? – Правильно, 77.3. Кажется, всё просто – мы объявляем ещё одну переменную «b» и в неё помещаем сумму чисел 32 и того, которое ранее поместили в переменную «a». Просто, да не совсем. Во-первых, сами арифметические операции часто пытаются неявно привести значение из переменных, которые служат операндами к числовому типу и это не всегда удаётся. Во-вторых, что произойдёт, например, если мы число 32 забёрём в одинарные или двойные кавычки, то есть превратим в строку? Воспользуемся тем, что переменные «a» и «b» мы уже объявили выше – слово «let» перед ними больше писать не следует, перепишем (а точнее дополним) наш скрипт такими строками:
a = 45.3
b = ‘32’ + a;
alert(b);
Упс, мы получаем 3245.3. Как так вышло? Мы думаем, что в переменную «b» мы поместили сумму двух операндов, но так как первый из них – строка, 32 забрано в апострофы, помните? То и весь результат считается строкой. В этом случае второй операнд – то, что находилось в переменной «a», тоже интерпретируется как строка и добавляется в конец предыдущей строки. А что произойдёт, если мы операнды поменяем местами? Как теперь они будут интерпретироваться? допишем наш скрипт так:
a = 45.3
b = a + ‘32’;
alert(b);
В результате опять что-то не то. Получаем 45.332. Это опять произошло из-за того, что один из операндов был строкой. Оба операнда интерпретируются как строки, только теперь их порядок поменялся. А сможем ли мы оба операнда использовать как числа? Да, можем, но в этом случае нам необходимо явно преобразовать строку к числовому типу, для этого воспользуемся функцией Number. И помните, в JavaScript регистр имеет значение.
a = 45.3;
b = a + Number('32');
alert(b);
Свершилось, как и в первом примере мы получаем 77.3. Выходит, мы сложили число, которое поместили в переменную «a», и число, в которое преобразовали строку ‘32’. А что произойдёт, если в эту строку мы поместим не только цифры, но и символы алфавита, проще говоря – буквы? Перепишем скрипт так:
a = 45.3;
b = a + Number('32пкsd');
alert(b);
Упс, выводится строка «NaN». Возвращаемся к прошлой заметке и читаем в ней, что NaN – специальное значение, которое обозначает ошибку в арифметическом действии. Стало быть, следует помнить, что строку, в которой записано не только число, но и другие символы функция Number не осилит.
Однако, это мы всё складывали, но есть и такие арифметические действия, которые могут сами пытаться преобразовать строки к числовому представлению, например – деление.
alert( '32' / '8');
В результате выполнения этой команды мы получим 4, хотя оба операнда были строками, так уж работает деление. Поэкспериментируйте на досуге с остальными арифметическими действиями, чтобы точно понимать, какого от них стоит ждать результата, но всегда помните – неявные преобразования типов могут быть очень коварными. Если вы желаете работать с операндами как с числами (мало ли что там прилетит в той или иной переменной, где её значение может много раз поменяться по ходу выполнения скрипта), то преобразовывайте ваши переменные явно.
Сама по себе функция alert тоже не так уж проста. Она при определённых условиях умеет неявно преобразовывать то, что ей передано в строки. Заменим в предыдущем примере знак деления снова на +, а строки заменим на числа.
alert( 32 + 8);
Услышав, что alert преобразовывает в строку то, что ей передали, что мы рассчитываем увидеть? Сложение двух строк и результат 328? Как бы не так, сначала числа будут сложены, и только потом результат выведется в виде строки, так что получаем 40. А вот если перед этим в alert поместить строку с комментарием, то и числа будут интерпретироваться как строки. Все эти тонкости следует помнить, а ещё лучше – тестировать на примерах, что там у вас получается. В следующем примере используем явное преобразование чисел в строки.
a = 32;
b = 8;
alert(String(a) + String(b));
В результате получим именно сложение двух строк 328. Точнее операцию сложения двух и более строк называют конкатенацией. Этот пример показывает, как передать в alert более одной строки. Я воспользуюсь этим и в скрипт, который помещу для вас в репозиторий на GitHub-е, добавлю для наглядности комментарии. Кстати, предпоследний пример без комментария выведет в результате 40, а с комментарием – 328. Такие вот, непростые эти неявные преобразования, всегда о них помните, когда пишете свои сценарии.
Boolean
Если в переменную поместить значение логического типа Boolean, то и его можно преобразовать в строку, например.
a = true;
b = String(a);
alert('Значение переменной a = ' + a + ', а её тип - ' + typeof a);
alert('Значение переменной b = ' + b + ', а её тип - ' + typeof b);
Легко убедиться, что при одинаковых вроде бы значениях, переменная «a» имеет логический тип Boolean, а переменная «b» - уже обычная строка. Прошу также запомнить оператор typeof, который и позволяет узнать на любом этапе, какой тип у переменной или выражения, находящегося за ним. Очень полезный оператор и часто используется при проверках, когда необходимо выяснить, является ли значение той или иной переменной, значением конкретного типа, но об этом поговорим в других заметках.
Точно также как мы логическое значение превратили в строку, можно и строку перевести в Boolean. Это даже интереснее. Давайте в наши переменные поместим строки (одну из них сделаем пустой) и явно их преобразуем к логическому типу. Что же мы увидим?
a = Boolean('Какая-то не пустая строка');
b = Boolean(''); // преобразуем в Boolean пустую строку
alert('Значение переменной a = ' + a);
alert('Значение переменной b = ' + b);
Для кого-то может стать полной неожиданностью, но пустая строка преобразовывается к значению false – ложь. А любая непустая к true – истина. То же самое произойдёт и с числами, только в ложь превращается число «0», а любые отличные от нуля числа превратятся в true. Программисты помнят об этой особенности и в качестве истины (true) часто используют число «1», а в качестве лжи (false) – «0». Однако стоит быть осторожным, если нуль появится в переменной как строка, то это уже будет не пустая строка, а значит и значение получится true.
Заключение
Трёх этих преобразований: к строке – String, к числу – Number и к логическому типу – Boolean, обычно хватает для написания довольно больших сценариев. Следует только помнить, что для нестандартных значений преобразование к числу работает так:
Неопределённое значение undefined превращается в NaN, true становится единицей (1), false превращается в нуль (0), особое значение null тоже превращается в нуль (0).
Cтроки, превращаясь в числа обрабатываются так: сначала убираются начальные и конечные пробелы в строке, если они есть, если после этого остаётся пустая строка, она превращается в нуль (0), иначе JavaScript пытается получить число. Если кроме цифр в строке есть другие символы (не десятичный разделитель), то выводится ошибка – NaN.
При приведении к логическому типу неопределённое значение undefined, null, пустая строка или нуль превращаются в false, все прочие значения – в true.