21 вересня 2023 р.

Типи даних

Значення в JavaScript завжди має певний тип даних. Наприклад, рядок або число.

У JavaScript є вісім основних типів даних. У цьому розділі ми розглянемо їх в цілому, а в наступних — детально поговоримо про кожен з них.

Ми можемо призначити змінній будь-який тип даних. Наприклад, в один момент змінна може бути рядком, а в інший – числом:

// тут не буде помилки
let message = "привіт";
message = 123456;

Мови програмування, які дають змогу таке робити, називаються “динамічно типізованими”. Мається на увазі, що типи даних визначені, але змінні не прив’язанні до жодного типу.

Число (number)

let n = 123;
n = 12.345;

Тип number представляє і цілі числа, і числа з рухомою точкою.

Є багато операцій, що можна робити з числами, наприклад, множення *, ділення /, додавання +, віднімання - тощо.

Окрім звичайних чисел, є так звані “спеціальні числові значення”, що також мають відношення до цього типу даних: Infinity, -Infinity і NaN.

  • Infinity являє собою математичну нескінченність ∞. Це спеціальне значення, що є більшим за будь-яке число.

    Ми можемо отримати його як результат ділення на нуль:

    alert(1 / 0); // Infinity

    Або безпосередньо посилатися на нього:

    alert(Infinity); // Infinity
  • NaN (Not a Number) являє собою помилку обчислення. Це є результат неправильної або невизначеної математичної операції, наприклад:

    alert("not a number" / 2); // NaN, таке ділення є помилковим

    NaN є “причепливим” (“заразливим”). Будь-яка подальша математична операція з NaN повертає NaN:

    alert( NaN + 1 ); // NaN
    alert( 3 * NaN ); // NaN
    alert( "not a number" / 2 - 1 ); // NaN

    Отже, якщо десь у математичному виразі є NaN, він поширюється на весь результат (є лише один виняток: результатом операції NaN ** 0 буде 1).

Математичні операції є безпечними

Обчислення є “безпечним” в JavaScript. Ми можемо робити будь-що: ділити на нуль, звертатися до нечислового рядка як до числа тощо.

Виконання скрипту ніколи не зупиниться з фатальною помилкою (не “вмре”). У найгіршому випадку ми отримаємо в результаті NaN.

Спеціальні числові значення формально належать до типу “number”. Хоча, звісно, вони не є числами у загальноприйнятому розумінні.

Докладніше роботу з числами ми розглянемо у розділі Числа.

BigInt

У JavaScript, тип “number” не може містити числа більші за (253-1) (це 9007199254740991), або менші за -(253-1) для від’ємних чисел.

Якщо бути дійсно точним, тип “number” може зберігати більші цілі числа (до 1,7976931348623157 * 10308), але поза межами безпечного діапазону цілих чисел ±(2 53-1) виникне помилка точності, оскільки не всі цифри вміщуються у фіксованому 64-бітному сховищі. Тому може бути збережено “приблизне” значення.

Наприклад, ці два числа (прямо над безпечним діапазоном) однакові:

console.log(9007199254740991 + 1); // 9007199254740992
console.log(9007199254740991 + 2); // 9007199254740992

Таким чином, усі непарні цілі числа, більші за (253-1), взагалі не можна зберігати в типі “number”.

Для більшості задач діапазону ±(253-1) цілком достатньо, але інколи нам потрібен весь діапазон дійсно великих цілих чисел, напр. для криптографії або міток часу з точністю до мікросекунд.

Нещодавно в мову був доданий тип BigInt для представлення цілих чисел довільної довжини.

Значення з типом BigInt створюється через додавання n у кінець цілого числа:

// буква "n" у кінці означає, що це число типу BigInt
const bigInt = 1234567890123456789012345678901234567890n;

Через те, що тип BigInt рідко використовується, ми не розглядатимемо його в цьому розділі, проте ми винесли його в окремий розділ BigInt. Прочитайте його, якщо вам потрібні такі великі числа.

Проблеми із сумісністю

Цієї миті, підтримка типу BigInt є в останніх версіях Firefox/Chrome/Edge/Safari, але не в IE.

На сайті MDN є таблиця сумісності, де показано, які версії браузерів підтримують тип BigInt.

Рядок (string)

Рядок у JavaScript має бути оточений лапками.

let str = "Привіт";
let str2 = 'Одинарні лапки також дозволяються';
let phrase = `так можна вставляти ${str}`;

У JavaScript є три типи лапок.

  1. Подвійні лапки: "Привіт".
  2. Одинарні лапки: 'Привіт'.
  3. Зворотні лапки: `Привіт`.

Подвійні та одинарні лапки є “звичайними”. Тобто немає ніякої різниці, які саме використовувати.

Зворотні лапки є розширенням функціональності. Вони дають змогу вбудовувати змінні та вирази в рядок, обрамляючи їх в ${…}, наприклад:

let name = "Іван";

// вбудована змінна
alert(`Привіт, ${name}е!`); // Привіт, Іване!

// вбудований вираз
alert(`результат: ${1 + 2}`); // результат: 3

Вираз всередині ${…} обчислюється, а результат обчислення стає частиною рядка. Ми можемо вбудувати будь-що: змінну name, або арифметичний вираз 1 + 2, або щось набагато складніше.

Будь ласка, зауважте, що вбудовування можна робити тільки зі зворотними лапками. Інші типи лапок не мають функціональності вбудовування!

alert("результат: ${1 + 2}"); // результат: ${1 + 2} (подвійні лапки не мають ніякого впливу)

Більш детально ми будемо висвітлювати рядки в розділі Рядки.

Немає типу символ (character).

У деяких мовах є спеціальний тип “character” для позначення єдиного символу. Наприклад, у мовах C та Java це char.

У JavaScript немає такого типу. Є єдиний тип: string. Рядок може містити нуль символів (бути пустим), один символ або більше.

Булевий або логічний тип (boolean)

Логічний тип може приймати лише два значення: true (істина) та false (хиба).

Цей тип зазвичай використовується для зберігання значень так/ні: true означає “так, вірно”, а false означає “ні, не вірно”.

Наприклад:

let nameFieldChecked = true; // так, ім’я було перевірене
let ageFieldChecked = false; // ні, вік не був перевіреним

Логічне значення також можна отримати як результат порівняння:

let isGreater = 4 > 1;

alert(isGreater); // true (результат порівняння — "так")

Більш глибоко ми охопимо булеві значення у розділі Логічні оператори.

Значення “null”

Спеціальне значення null не належить до жодного з описаних вище типів.

Воно формує окремий власний тип, який містить лише значення null:

let age = null;

В JavaScript null не є “посиланням на об’єкт, що не існує” або “покажчиком на null”, як може бути в інших мовах програмування.

Це лише спеціальне значення, яке представляє “нічого”, “порожнє” або “невідоме значення”.

У наведеному вище коді зазначено, що значення змінної age невідоме.

Значення “undefined”

Спеціальне значення undefined також стоїть окремо. Воно представляє власний тип, подібний до “null”.

undefined означає, що “значення не присвоєно”.

Якщо змінна оголошена, але їй не присвоєне якесь значення, тоді значення такої змінної буде undefined:

let age;

alert(age); // покаже "undefined"

Технічно, є можливість явно призначити undefined змінній:

let age = 100;

// змінюємо значення на undefined
age = undefined;

alert(age); // "undefined"

…Але ми не рекомендуємо так робити. Як правило, ми використовуємо null, щоби присвоїти змінній значення “порожнє” або “невідоме”, тоді як undefined зарезервоване для позначення початкового значення для не присвоєних речей.

Об’єкти (object) та символи (symbol)

Тип object є особливим типом.

Усі інші типи називаються “примітивами”, тому що їхні значення можуть містити тільки один елемент (це може бути рядок, число, або будь-що інше). В об’єктах же зберігаються колекції даних і складніші структури.

Об’єкти є важливою частиною мови, тому ми окремо розглянемо їх у розділі Об’єкти після того, як дізнаємося більше про примітиви.

Тип symbol використовується для створення унікальних ідентифікаторів в об’єктах. Ми згадали цей тип для повноти, проте докладніше вивчимо його після об’єктів.

Оператор typeof

Оператор typeof повертає тип аргументу. Це корисно, коли ми хочемо обробляти значення різних типів по-різному або просто хочемо зробити швидку перевірку.

Виклик typeof x повертає рядок із назвою типу:

typeof undefined // "undefined"

typeof 0 // "number"

typeof 10n // "bigint"

typeof true // "boolean"

typeof "foo" // "string"

typeof Symbol("id") // "symbol"

typeof Math // "object"  (1)

typeof null // "object"  (2)

typeof alert // "function"  (3)

Останні три рядки можуть потребувати додаткового пояснення:

  1. Math — це вбудований об’єкт, який забезпечує математичні операції. Ми вивчимо його в розділі Числа. Тут він використаний лише як приклад об’єкта.
  2. Результатом typeof null є "object". Це офіційно визнана помилка поведінки typeof, що є ще з ранніх днів JavaScript і зберігається для сумісності. Безперечно, null не є об’єктом. Це особливе значення з власним типом. У цьому разі поведінка typeof некоректна.
  3. Результатом typeof alert є "function", тому що alert — це функція. Ми будемо вивчати функції в наступних розділах, де ми також побачимо, що в JavaScript немає спеціального типу “function”. Функції належать до типу “об’єкт”. Але typeof трактує їх по-іншому, повертаючи "function". Це також присутнє з ранніх днів JavaScript. Технічно, така поведінка не зовсім правильна, але може бути зручною на практиці.
Синтаксис typeof(x)

Можливо ви зустрічали інший синтаксис: typeof(x). Це те саме, що typeof x.

Щоби було зрозуміло: typeof – це оператор, а не функція. Тут дужки не є частиною typeof. Це щось на кшталт математичних дужок для групування.

Зазвичай, такі дужки містять математичні вирази, як (2 + 2), але тут вони містять лише один аргумент (x). Ці дужки дають змогу опустити пробіл між оператором typeof та його аргументом, і декому це подобається.

Тому вони надають перевагу синтаксису typeof(x), проте синтаксис typeof x набагато поширеніший.

Підсумки

У JavaScript є 8 основних типів.

  • Сім примітивних типів даних:

    • number для будь-яких чисел: цілих або з рухомою точкою. Цілі числа обмежені до ±(253-1).
    • bigint для цілих чисел довільної довжини.
    • string для рядків. Рядок може мати нуль або більше символів, немає окремого типу для одного символу.
    • boolean для true/false.
    • null для невідомих значень – автономний тип, який має єдине значення null.
    • undefined для не присвоєних значень – автономний тип, який має єдине значення undefined.
    • symbol для унікальних ідентифікаторів.
  • І один непримітивний тип даних:

    • object для складних структур даних.

Оператор typeof дає змогу нам бачити, який тип зберігається в змінній.

  • Зазвичай використовують синтаксис typeof x, проте typeof(x) також можливий.
  • Повертає рядок із назвою типу, як-от "string".
  • Для null повертає "object" – це помилка в мові, null насправді не об’єкт.

У наступних розділах ми зосередимося на примітивних значеннях, а коли ознайомимося з ними, то перейдемо до об’єктів.

Завдання

важливість: 5

Який буде результат виконання скрипту?

let name = "Ілля";

alert( `привіт ${1}` ); // ?

alert( `привіт ${"name"}` ); // ?

alert( `привіт ${name}` ); // ?

Зворотні лапки вбудовують вираз, що знаходиться всередині ${...}, у рядок.

let name = "Ілля";

// вираз — число 1
alert( `привіт ${1}` ); // привіт 1

// вираз є рядком "name"
alert( `привіт ${"name"}` ); // привіт name

// вираз є змінною, яка вбудовується
alert( `привіт ${name}` ); // привіт Ілля
Навчальна карта

Коментарі

прочитайте це, перш ніж коментувати…
  • Якщо у вас є пропозиції, щодо покращення підручника, будь ласка, створіть обговорення на GitHub або одразу створіть запит на злиття зі змінами.
  • Якщо ви не можете зрозуміти щось у статті, спробуйте покращити її, будь ласка.
  • Щоб вставити код, використовуйте тег <code>, для кількох рядків – обгорніть їх тегом <pre>, для понад 10 рядків – використовуйте пісочницю (plnkr, jsbin, codepen…)