Что произойдет, если мы попробуем умножить число на строку? JavaScript вернет NaN
(не число) — то самое значение. Оно возникает там, где вместе используются несовместимые значения. В данном случае число и строка:
3 * 'Dracarys' // NaN
Внутри высокоуровневых языков программирования данные разделяются по типам. Любая строка относится к типу String, а числа — к типу Number и BigInt (очень большие числа). Зачем нужны типы? Для защиты программы от трудноуловимых ошибок. Типы определяют две вещи:
- Возможные (допустимые) значения. Например, числа в JavaScript делятся на два типа: Number и BigInt. Первые — это все числа ниже определенного порога (его можно посмотреть), вторые — выше. Такое разделение связано с техническими особенностями работы аппаратуры.
- Набор операций, которые можно выполнять над этим типом. Например, операция умножения имеет смысл для типа «целые числа». Но не имеет смысла для типа «строки»: умножать слово «мама» на слово «блокнот» — бессмыслица.
JavaScript ведет себя двояко, когда встречается с нарушениями. В некоторых ситуациях он ругается на недопустимость операции и завершается с ошибкой. В других — программа продолжает работать. В этом случае недопустимая операция возвращает что-то похожее на NaN
, как в примере выше.
Каким образом JavaScript понимает, что за тип данных перед ним? Достаточно просто. Любое значение где-то инициализируется и, в зависимости от способа инициализации, становится понятно, что перед нами. Например, числа — это просто числа без дополнительных символов, кроме точки для рациональных чисел. А вот строки всегда ограничены специальными символами (в JavaScript три разных варианта). Например, такое значение '234'
– строка, несмотря на то, что внутри нее записаны цифры.
JavaScript позволяет узнать тип данных с помощью оператора typeof
:
typeof 3 // number
typeof 'Game' // string
Типы данных Number, BigInt и String — это примитивные типы. Но есть и другие. В JavaScript встроен составной тип Object (а на его базе массивы, даты и другие). С его помощью можно объединять данные разных типов в одно значение, например, мы можем создать пользователя, добавив к нему имя и возраст:
// Этот синтаксис изучается далее на Хекслете
const user = { name: 'Toto', age: 33 }
По-английски строки в программировании называются "strings", а строчки текстовых файлов — "lines". Например, в коде выше есть две строчки (lines), но только одна строка (string). В русском иногда может быть путаница, поэтому во всех уроках мы будем говорить строка для обозначения типа данных «строка», и строчка для обозначения строчек (lines) в файлах.
undefined
Объявление переменных возможно и без указания конкретного значения. Что будет выведено на экран, если ее распечатать:
let name
console.log(name) // ?
На экране появится undefined
, специальное значение особого типа, которое означает отсутствие значения. Undefined активно используется самим JavaScript в самых разных ситуациях, например, при обращении к несуществующему символу строки:
const name = 'Arya'
console.log(name[8])
Смысл (семантика) значения undefined
именно в том, что значения нет. Однако, ничто не мешает написать такой код:
let key = undefined
И хотя интерпретатор позволяет такое сделать, это нарушение семантики значения undefined
, ведь в этом коде выполняется присваивание, а значит — подставляется значение.
JavaScript — один из немногих языков, в которых в явном виде присутствует понятие undefined
. В остальных языках его функцию выполняет значение null
, которое, кстати, тоже есть в JavaScript.
Вопрос на самопроверку. Почему нельзя объявить константу без указания значения?
Числа с плавающей точкой
В математике существуют разные виды чисел, например, натуральные – это целые числа от одного и больше, или рациональные – это числа с точкой, например 0.5. С точки зрения устройства компьютеров, между этими видами чисел – пропасть. Попробуйте ответить на простой вопрос, сколько будет 0.2 + 0.1? А теперь посмотрим, что на это скажет JavaScript:
0.2 + 0.1 // 0.30000000000000004
Операция сложения двух рациональных чисел внезапно привела к неточному вычислению результата. Тот же самый результат выдадут и другие языки программирования. Такое поведение обуславливается ограничениями вычислительных мощностей. Объем памяти, в отличие от чисел, конечен (бесконечное количество чисел требует бесконечного количества памяти для своего хранения).
Рациональные числа не выстроены в непрерывную цепочку, между 0.1 и 0.2 бесконечное множество чисел. Соответственно возникает серьезная проблема, а как хранить рациональные числа? Это интересный вопрос сам по себе. В интернете множество статей, посвященных организации памяти в таких случаях. Более того, существует стандарт, в котором описано, как это делать правильно, и подавляющее число языков на него опирается.
Для нас, как для разработчиков, важно понимать, что операции с плавающей точкой неточны (эту точность можно регулировать), а значит при решении задач, связанных с подобными числами, необходимо прибегать к специальным трюкам, которые позволяют добиться необходимой точности.
Явное преобразование типов
В программировании регулярно встречаются задачи, когда один тип данных нужно преобразовать в другой — например, при работе с формами на сайтах. Данные формы всегда приходят в текстовом виде, даже если значение — число. Вот как его можно преобразовать:
const number = parseInt('345')
console.log(number) // => 345
parseInt()
— это функция, в которую передается значение, чтобы его преобразовать. Функция ведет себя подобно арифметическим операциям, но делает особые действия. Вот еще несколько примеров:
const value = '0'
// Внутри скобок можно указывать переменную
const number1 = parseInt(value)
console.log(number1) // => 0
// Или конкретное значение
const number2 = parseInt('10')
console.log(number2) // => 10
// Если преобразуется число с плавающей точкой
// то отбрасывается вся дробная часть
const number5 = parseInt(3.5)
console.log(number5) // => 3
Точно так же можно преобразовать строку в число с плавающей точкой с помощью parseFloat()
:
const value3 = parseFloat('0.5')
console.log(value3) // 0.5