16 липня 2023 р.

Методи примітивів

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

Розгляньмо різницю між примітивами та об’єктами.

Примітив

  • є значенням примітивного типу
  • існує 7 типів примітивів: string, number, bigint, boolean, symbol, null та undefined.

Об’єкт

  • можна зберігати декілька значень як властивості.
  • може бути створений за допомогою {}, наприклад: {name: "Іван", age: 30}. В JavaScript існують й інші об’єкти: функції — це теж об’єкти.

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

let john = {
  name: "John",
  sayHi: function() {
    alert("Привіт, друже!");
  }
};

john.sayHi(); // Привіт, друже!

Отже, ми створили об’єкт john з методом sayHi.

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

Але за все потрібно платити!

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

Примітив як об’єкт

Маємо парадокс, з яким зустрічається автор JavaScript:

  • Є багато речей, які можна було б зробити з примітивом-рядком або числом. Було б добре отримати доступ до цих методів.
  • Примітиви повинні бути максимально швидкими та легкими.

Рішення виглядає трохи дивно, але так і є:

  1. Примітиви залишаються примітивами. Лише значення, як ви і хотіли.
  2. JavaScript дозволяє отримати доступ до методів та властивостей рядків, чисел, булеанів та символів.
  3. Для цього створюється спеціальний “об’єкт обгортка” з додатковою функціональністю, який потім знищується.

Для кожного примітиву створюється своя “обгортка”: String, Number, Boolean, Symbol та BigInt. Отже, вони містять різні набори методів.

Наприклад: існує такий метод для рядка, як str.toUpperCase(), який поверне рядок str з великими літерами.

Ось як він працює:

let str = "Привіт";

alert( str.toUpperCase() ); // ПРИВІТ

Не складно, так? Ось що саме трапляється в str.toUpperCase():

  1. Рядок str є примітивом. Тому під час звернення до його властивості створюється спеціальний об’єкт, який знає значення рядка і має корисні методи, такі як toUpperCase().
  2. Цей метод виконується і повертає новий рядок (що показує alert).
  3. Спеціальний об’єкт руйнується, залишаючи лише примітив str.

Отже, примітиви можуть надавати методи, але залишаються “легкими”.

Двигун JavaScript добре оптимізує цей процес. Він навіть може пропустити створення додаткового об’єкта взагалі. Але він все ще повинен дотримуватися специфікації і вести себе так, наче він її створює.

Число має свої методи, наприклад: toFixed(n) – округлює число до заданої точності:

let n = 1.23456;

alert( n.toFixed(2) ); // 1.23

Ми переглянемо більш конкретні методи у розділах Числа та Рядки.

Конструктори String/Number/Boolean лише для внутрішнього використання

Деякі мови як Java дозволяють явно створювати “об’єкт обгортку” для примітивів, використовуючи синтаксис як new Number(1) або new Boolean(false).

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

Наприклад:

alert( typeof 0 ); // "number"

alert( typeof new Number(0) ); // "object"!

Об’єкти завжди повертають true в if, отже ми побачимо alert:

let zero = new Number(0);

if (zero) { // zero є true, тому що це об’єкт
  alert( "zero є true!?!" );
}

З іншого боку, використання тих же самих функцій String/Number/Boolean без new є абсолютно розумною і корисною річчю. Вони перетворюють значення у відповідний тип: рядок, число або булеве значення (примітиву).

Наприклад, це цілком правильно:

let num = Number("123"); // конвертує рядок в число
null/undefined не мають методів

Винятки становлять спеціальні примітиви null і undefined. Вони не мають відповідних “об’єктів обгорток” і не надають ніяких методів. Ми можемо назвати їх “найпримітивнішими”.

Спроба доступу до властивості такого значення дасть помилку:

alert(null.test); // помилка

Підсумки

  • Примітиви, крім null і undefined, дають багато корисних методів. Ми вивчимо їх у наступних розділах.
  • Формально, ці методи працюють через тимчасові об’єкти, але двигун JavaScript оптимізовано для швидкого виконання цих операцій, тому нам не треба хвилюватися.

Завдання

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

Розглянемо наступний код:

let str = "Привіт";

str.test = 5;

alert(str.test);

Як ви думаєте, чи буде це працювати? Що буде показано?

Спробуйте запустити:

let str = "Привіт";

str.test = 5; // (*)

alert(str.test);

В залежності від того, втановлений у вас use strict чи ні, результати будуть наступними:

  1. undefined (без суворого режиму)
  2. Помилка (суворий режим)

Чому? Давайте повторимо те, що відбувається в рядку, який позначено (*):

  1. Коли ми намагаємося отримати доступ до str, створюється “об’єкт обгортка”.
  2. В суворому режимі, спроба запису викличе помилку.
  3. В іншому випадку, операція здійсниться і об’єкт отримає властивість test, але після цього “об’єкт обгортка” зникне, отже, якщо код виконується не в суворому режимі, на останньому рядку str не матиме властивості test.

Цей приклад чітко показує, що примітиви не є об’єктами.

Вони не можуть зберігати додаткові дані.

Навчальна карта