Перейти к содержанию

Значения и типы JavaScript

В первой программе сообщение было готовой строкой. Каталог требует отдельных данных: название курса, число уроков и признак доступности. Они могут отображаться рядом, но вычисления над ними различаются. С числом можно складывать, строку можно соединять с другой строкой, логическое значение удобно использовать для выбора действия.

В этом уроке будем описывать одну карточку будущего каталога. Заменяйте содержимое app.js показанными полными примерами и обновляйте документ из предыдущего урока. Пока не создаём HTML из JavaScript: результат наблюдаем в консоли, чтобы внешний вид страницы не скрывал смысл операций.

Данные одного курса

Запишите название, количество уроков и признак публикации:

const title = 'Современный JavaScript';
const lessons = 20;
const published = true;
console.log(title);
console.log(lessons + 1);
console.log(published);

const вводит имя, через которое далее обращаемся к значению; подробнее выбор объявления рассмотрим следующим шагом. Сейчас важно различие правых частей: текст заключён в кавычки, число записано без них, а true является специальным логическим значением. Ожидаются название, число двадцать один и значение true.

Само наличие цифр внутри кавычек не делает строку числом. Значение '20' удобно хранить как текст, но оно не имеет того же смысла, что 20, при всех операциях. Например, текстовое значение может содержать ведущий ноль, который важен для кода, но не для количества уроков. Тип выбираем по назначению данных, а не по тому, как они выглядят на экране.

Посмотрим на два варианта сложения в самостоятельном фрагменте:

console.log(20 + 4);
console.log('20' + 4);
console.log(typeof 20);
console.log(typeof '20');

Ожидаемый вывод:

24
204
number
string

Во втором выражении знак + соединяет текстовые представления. Внешне результат состоит из цифр, но числового сложения не произошло. Оператор typeof помогает посмотреть тип, когда источник данных ещё неизвестен. Для уверенного проектирования важнее заранее договориться о формате, чем проверять тип каждой промежуточной переменной без причины.

Преобразование на границе ввода

Позднее форма будет отдавать строковые значения. Уже сейчас смоделируем такой ввод и явно преобразуем его:

const enteredLessons = '20';
const numericLessons = Number(enteredLessons);
console.log(numericLessons + 4);
console.log(Number.isFinite(numericLessons));

Ожидаются 24 и true. Вызов Number выполняет преобразование, а Number.isFinite спрашивает, получилось ли конечное число. Это разные операции: преобразование само по себе ещё не доказывает, что значение допустимо для нашей предметной области.

Пустая строка при таком преобразовании даёт ноль. Строка 'двадцать' даёт специальное числовое значение NaN, обозначающее неудачный числовой результат. Поэтому реальная форма сначала должна отличить отсутствующий ввод, а затем проверить число. Мы не будем исправлять ввод заменой любого неверного значения на ноль: такое решение сделало бы ошибочный курс похожим на настоящий курс без уроков.

Для количества нам понадобятся целое положительное число и дополнительная проверка Number.isInteger. Двадцать с половиной является корректным числом языка, но неверным количеством уроков в принятой модели. Отделяйте ограничения JavaScript от ограничений приложения: язык разрешает больше значений, чем конкретная карточка курса.

Типы и поведение преобразований описаны в MDN о типах данных. Наш пример специально показывает только небольшую часть системы типов; знакомство с BigInt и Symbol не требуется для этого каталога.

Отсутствие данных и форматирование

undefined и null оба встречаются там, где нет обычного значения, однако помогают выразить разные ситуации. Неинициализированное объявление let получает undefined. Значение null можно назначить явно, когда приложению нужно обозначить отсутствие выбранного курса. Пока достаточно понимать, что это не пустая строка и не числовой ноль.

Не используйте typeof null как проверку наличия объекта: исторически его результат равен строке 'object'. Для явного отсутствия пишут сравнение с null; проверку настоящих записей каталога подробно построим в уроке об ошибках. Такая оговорка нужна потому, что общее правило «посмотрел typeof и всё известно» здесь не работает.

Для сообщения, которое объединяет текст и вычисленное число, удобно использовать шаблонную строку:

const title = 'Современный JavaScript';
const lessons = 20;
console.log(`${title}: уроков ${lessons}`);

Обратные кавычки отличаются от обычных. Внутри них конструкция ${...} содержит выражение, результат которого подставляется в строку. Ожидается сообщение Современный JavaScript: уроков 20. Преобразование для отображения не меняет исходный тип lessons: в последующих вычислениях переменная всё ещё содержит число.

Обратите внимание на границу ответственности. Число хранится как число, а текст создаётся только там, где нужен человеку. Если сохранить '20 уроков' вместо количества, дальнейший подсчёт потребует разбирать уже оформленную фразу. Кроме того, изменение языка интерфейса начнёт влиять на вычисления. Отдельные данные позволяют независимо менять подпись и логику.

Для самостоятельного наблюдения поставьте в enteredLessons значения '0', '', '12.5' и 'двенадцать'. Предскажите отдельно результат преобразования, проверку конечности и допустимость для карточки. Ожидаемые результаты этого эксперимента показывают, почему одно слово «число» ещё не является полноценным правилом ввода.

Число и единица измерения

Количество уроков является безразмерным целым числом, но не все будущие данные каталога будут такими. Например, время чтения может храниться в минутах, а размер файла — в байтах. Сам тип number не сообщает единицу. Названия readingMinutes и fileBytes делают договорённость явной и предотвращают случайное сложение несопоставимых величин.

Обычные числа JavaScript используют двоичное представление с ограниченной точностью. Поэтому выражение с десятичными дробями не следует бездумно превращать в финансовый расчёт. Для нашего количества небольшие целые числа не требуют такого обходного решения. Важно ограничить объяснение именно задачей: выбор числового типа удобен для подсчёта уроков и ещё не решает все задачи с числами.

Оформление результата относится к интерфейсу. Сначала выполните сложение числовых значений, затем создайте подпись. Если соединять строки до расчёта, будущая проверка суммы получит текст, а не количество. Для наблюдения выведите рядом исходное значение и его typeof; затем отдельно выведите готовое сообщение. Вы увидите три разные вещи: данные, их тип и представление человеку. Такая модель сохраняется и после появления JSON или формы.

Строки сравниваются с учётом их содержания, включая пробелы и регистр. Название с пробелом в конце может выглядеть почти так же в интерфейсе, но это другое значение. Для обязательных названий позже используем trim, убирающий пробелы по краям. Код темы при этом не преобразуем из русской подписи: он задаётся отдельно и остаётся постоянным.

Не прибавляйте логическое значение к количеству ради краткости. Язык способен выполнить преобразование, но предметное действие «включить дополнительный урок» яснее выразить условием или именованной функцией. Неявные преобразования особенно трудно заметить после получения строк из формы. Чем ближе вход к внешней границе, тем важнее явное понимание ожидаемого типа.

Для названия мы пока не ограничиваем длину и не разбираем его на слова. Строковое значение представляет весь текст целиком. Операция отображения позднее передаст его в textContent, а не заставит интерпретировать как программу. Поэтому наличие кавычек внутри названия относится к правильной записи строки в исходнике, а не к дополнительному выполнению текста.

Теперь данные первого курса различаются по смыслу и типу. В следующем уроке сохраним эти данные, но добавим изменяемый выбор темы и рассмотрим, где имена доступны. Это позволит отделить постоянное описание курса от текущего состояния интерфейса.

Оглавление курса