1. Що таке JavaScript?
- JavaScript — це динамічна, прототипно-орієнтована мова програмування, яка використовується для створення інтерактивного контенту на вебсторінках. Вона підтримує подієве програмування, асинхронність і працює в браузері, а також на сервері через Node.js.
2. Які ключові слова використовуються для оголошення змінних у JavaScript?
var
-
Старий спосіб оголошення змінних.
-
Область видимості: функціональна (в межах функції, а не блоку).
-
Підтримує підняття (hoisting): змінну можна використовувати до оголошення, але значення буде undefined.
-
Не рекомендується через можливість помилок.
var x = 10;
let
-
Використовується для змінних, які можуть змінювати значення.
-
Область видимості: блочна (в межах {}).
-
Не дозволяє повторного оголошення в межах однієї області.
-
Не піддається підняттю з доступом до значення.
let y = 20; y = 30; // Можна змінити значення
const
-
Використовується для змінних, значення яких не змінюється.
-
Область видимості: блочна.
-
Потрібно обов’язково ініціалізувати при оголошенні.
-
Якщо змінна є об’єктом або масивом, значення властивостей можна змінювати, але саму змінну перевизначити не можна.
const z = 40; // z = 50; // Помилка
-
Рекомендації:
- Використовувати
const
для змінних, які не змінюються. - Використовувати
let
для змінних, які змінюють значення. var
уникати, якщо це не потрібно для специфічної підтримки старих браузерів.
- Використовувати
3. Перерахуйте типи даних у JavaScript.
- Примітивні:
string
number
boolean
null
undefined
bigint
symbol
- Складні:
object
(включаючи масиви, функції, дати тощо).
4. У чому різниця між функціональним (functional) і подієвим (event-driven) програмуванням у JavaScript?
-
Функціональне програмування:
- Базується на чистих функціях, які не мають побічних ефектів.
- Дані не змінюються, використовується іммутабельність.
- Код пишеться у вигляді композиції функцій (
map
,reduce
,filter
). - Наприклад: обробка даних у масиві через функції вищого порядку.
-
Подієве програмування:
- Реакція на події (
click
,hover
,async responses
). - Використовує слухачі (
event listeners
) та обробники подій (callbacks
). - Побудоване на взаємодії з подіями в середовищі (браузері чи Node.js).
- Наприклад: виклик функції при кліку на кнопку.
- Реакція на події (
5. У якому році відбувся перший реліз JavaScript, і в якому браузері він був вперше використаний?
- Перший реліз JavaScript відбувся в 1995 році. Він був вперше реалізований у браузері Netscape Navigator.
6. Чим відрізняється масив та обʼєкт? У яких випадках що використовуєте?
-
Масив:
- Використовується для зберігання впорядкованих елементів.
- Індексовані значення (0, 1, 2, …).
- Підходить для роботи з колекціями даних, де порядок важливий або коли потрібно виконувати операції типу сортування.
-
Обʼєкт:
- Використовується для зберігання пар "ключ-значення".
- Доступ до значень через ключі (не індекси).
- Підходить для зберігання даних з різними властивостями або для створення складних структур.
-
Використання:
- Масив: коли порядок елементів важливий або ви працюєте з колекцією однотипних елементів (наприклад, список користувачів).
- Обʼєкт: коли потрібно зберігати дані з різними властивостями або асоціативні пари (наприклад, профіль користувача з різними атрибутами).
7. Events в JavaScript. Розкажіть про event propagation, bubbling, delegation, preventing тощо.
- Event Propagation — це процес, при якому подія, що сталася на елементі, "поширюється" через DOM дерево. Є два основні етапи:
-
Bubbling (Спливання): Подія спочатку викликається на найбільш вкладеному елементі, потім вона спливає до батьківських елементів (від внутрішнього до зовнішнього). Наприклад, якщо клікнути на кнопку всередині контейнера, подія спочатку буде оброблятися кнопкою, потім контейнером, і так далі, поки не досягне кореневого елемента (document).
-
Capturing (Ловлення): Подія спочатку обробляється на найвищому рівні DOM дерева (наприклад, document), а потім спускається вниз до цільового елемента.
-
Event Delegation — це техніка обробки подій, коли ви додаєте один обробник подій на батьківський елемент, а не на кожен окремий дочірній елемент. Це дозволяє зменшити кількість обробників і є ефективним способом обробки подій на динамічно створених елементах.
-
Preventing Default Behavior (Запобігання стандартній поведінці):
- Метод event.preventDefault() дозволяє зупинити стандартну поведінку події. Наприклад, можна скасувати перезавантаження сторінки при натисканні на посилання або скасувати відправку форми.
-
stopPropagation() vs. stopImmediatePropagation():
- stopPropagation(): Зупиняє подальше поширення події по DOM, але не скасовує інші обробники подій на поточному елементі.
- stopImmediatePropagation(): Зупиняє подальше поширення події і скасовує інші обробники подій, що могли бути зареєстровані на тому самому елементі.
8. Чи можливо перевизначити const?
- Ні, значення, оголошене через const, не можна змінити. Це означає, що ви не можете переназначити змінну, оголошену з const, на нове значення. Однак, якщо const використовується для оголошення обʼєкта або масиву, ви все ще можете змінювати його вміст (наприклад, додавати властивості до обʼєкта або елементи до масиву). Тобто, const гарантує, що сама змінна не може бути переназначена, але не захищає від змін всередині складних типів даних (масивів, обʼєктів).
9. Чи відомі вам принципи DRY, KISS, YAGNI, SOLID?
- Так, ці принципи широко використовуються в програмуванні для забезпечення чистого, підтримуваного і ефективного коду.
-
DRY (Don't Repeat Yourself) — уникайте дублювання коду. Якщо одна й та сама логіка зустрічається в кількох місцях, варто створити спільну функцію або метод, щоб зробити код більш зручним для підтримки.
-
KISS (Keep It Simple, Stupid) — підтримуйте код простим і зрозумілим. Уникайте надмірної складності і зайвих абстракцій. Простота покращує підтримуваність і знижує ймовірність помилок.
-
YAGNI (You Aren't Gonna Need It) — не додавайте функціональність, яку наразі не потрібно. Створювати код тільки для майбутніх можливостей може призвести до зайвих витрат часу і складності.
-
SOLID — набір принципів для об'єктно-орієнтованого програмування, що допомагають створювати гнучкий, зрозумілий і підтримуваний код:
- S (Single Responsibility Principle) — кожен клас чи функція має виконувати одну задачу.
- O (Open/Closed Principle) — код має бути відкритим для розширення, але закритим для модифікації.
- L (Liskov Substitution Principle) — обʼєкти підкласів повинні заміняти обʼєкти батьківських класів без порушення роботи програми.
- I (Interface Segregation Principle) — не змушуйте класи реалізовувати інтерфейси, які вони не використовують.
- D (Dependency Inversion Principle) — залежності повинні бути від абстракцій, а не від конкретних класів.
10. У чому відмінності LocalStorage від SessionStorage?
-
LocalStorage:
- Зберігає дані без обмежень по часу, дані зберігаються навіть після закриття браузера або вкладки.
- Доступні для всіх вкладок і вікон того ж самого домену.
- Обмеження на обсяг — зазвичай 5-10 МБ на домен.
- Дані зберігаються, поки вони не будуть явно видалені.
-
SessionStorage:
- Дані зберігаються тільки в межах однієї сесії (до закриття вкладки або вікна браузера).
- Доступні тільки в тій самій вкладці або вікні, в якій були збережені.
- Обсяг схожий на LocalStorage (5-10 МБ).
- Дані видаляються автоматично при закритті вкладки або браузера.
-
Основні відмінності:
- Тривалість зберігання: LocalStorage — дані зберігаються постійно, SessionStorage — тільки на час сесії.
- Доступність: LocalStorage доступний для всіх вкладок, SessionStorage — тільки для поточної вкладки.
11. Що таке замикання (closure) в JavaScript і як воно працює?
-
Замикання (closure) — це функція, яка "запам'ятовує" оточення, в якому була створена. Це дозволяє функції доступ до змінних, навіть після того, як зовнішня функція, в якій вона була оголошена, завершила своє виконання.
-
Як це працює:
- Оточення: Кожна функція в JavaScript має доступ до змінних, які знаходяться в її власному оточенні (локальні змінні), а також до змінних, які були доступні в оточенні, де функція була створена.
- Замикання: Коли функція всередині іншої функції повертається або передається, вона все ще має доступ до змінних оточення, навіть якщо зовнішня функція вже завершила виконання.
-
Приклад:
function outer() { let counter = 0; // локальна змінна зовнішньої функції return function inner() { // внутрішня функція counter++; // доступ до змінної outer() console.log(counter); }; } const increment = outer(); // викликаємо outer, що повертає функцію inner increment(); // виведе 1 increment(); // виведе 2
12. Що таке Кукі (cookies) і як вони працюють в JavaScript?
-
Кукі (cookies) — це невеликі фрагменти даних, які вебсайт зберігає в браузері користувача. Вони використовуються для зберігання інформації, яка може бути використана для ідентифікації користувача, збереження налаштувань, відслідковування сесій тощо.
-
Як працюють кукі в JavaScript:
-
Зчитування кукі: Веб-браузер автоматично додає всі кукі для поточного домену до заголовка запиту, і JavaScript може отримати їх через document.cookie.
const cookies = document.cookie; console.log(cookies); // виведе всі кукі у вигляді рядка
-
Запис кукі: Кукі встановлюються за допомогою властивості document.cookie. Формат для встановлення кукі виглядає так:
document.cookie = "name=value; expires=Thu, 31 Dec 2025 23:59:59 UTC; path=/";
-
У цьому прикладі:
- "name=value" — це ключ-значення кукі.
- expires — вказує дату, коли кукі стане неактивним. Якщо не вказано, кукі буде тимчасовим і видалиться після закриття браузера.
- path — визначає, до якого шляху на сайті доступна кукі.
-
-
Видалення кукі: Щоб видалити кукі, потрібно встановити її термін придатності в минуле:
document.cookie = "name=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/";
-
Особливості:
- Термін дії: Кукі можуть бути тимчасовими або мати встановлений термін дії.
- Обмеження на розмір: Кожна кукі може зберігати до 4 КБ даних, і браузер зберігає до 20 кукі на домен.
- Обмеження на доступність: Кукі можуть бути доступні лише на тому домені і підкаталозі, де вони були встановлені.
- Безпека: Кукі можуть бути позначені як Secure (щоб передавались лише через HTTPS) і HttpOnly (щоб вони не були доступні через JavaScript).
-
Використання кукі:
- Ідентифікація користувача (наприклад, для збереження сесій).
- Збереження налаштувань користувача (темна/світла тема, мова сайту).
- Відслідковування статистики (аналітика).
- Кукі є важливим інструментом для взаємодії між клієнтом і сервером, але їх потрібно використовувати обережно через питання конфіденційності та безпеки.
13. Що таке область видимості змінної?
- Область видимості змінної — це частина коду, в межах якої до змінної можна отримати доступ. У JavaScript існують три основні типи області видимості:
- Глобальна область видимості (Global Scope):
-
Змінна доступна у всьому коді.
-
Змінні, оголошені поза будь-якими функціями або блоками, автоматично стають глобальними.
-
Глобальні змінні створюються з використанням ключових слів var, let, const, або без них (хоча останнє — погана практика).
var globalVar = "I am global"; // доступна у всьому коді function test() { console.log(globalVar); // доступ до глобальної змінної } test();
- Функціональна область видимості (Function Scope):
-
Змінні, оголошені всередині функції з використанням var, доступні лише в межах цієї функції.
-
Ця область видимості застосовується лише до var. Змінні let і const підкоряються блочній області видимості.
function test() { var localVar = "I am local"; console.log(localVar); // доступна всередині функції } test(); console.log(localVar); // помилка: localVar не визначена
- Блочна область видимості (Block Scope):
-
Змінні, оголошені з використанням let або const, доступні тільки всередині блоку {}.
-
Не застосовується до змінних, оголошених через var.
{ let blockVar = "I am block scoped"; const blockConst = "I am also block scoped"; console.log(blockVar); // доступна } console.log(blockVar); // помилка: blockVar не визначена
-
Вкладені області видимості:
- Внутрішня область може отримати доступ до змінних з зовнішньої області, але не навпаки.
function outer() { let outerVar = "outer"; function inner() { console.log(outerVar); // доступ до змінної зовнішньої функції } inner(); } outer();
-
Hoisting (Підняття):
-
У JavaScript змінні, оголошені через var, "піднімаються" на початок своєї області видимості, але без ініціалізації.
-
Змінні, оголошені через let і const, також піднімаються, але недоступні до моменту їхньої ініціалізації (це називається "Temporal Dead Zone").
console.log(a); // undefined var a = 10; console.log(b); // помилка let b = 20;
-
14. Що таке анонімна функція?
-
Анонімна функція — це функція, яка не має імені. Вона часто використовується там, де функцію потрібно створити швидко і немає необхідності використовувати її повторно.
-
Приклади анонімних функцій у JavaScript:
-
Функція як аргумент: Анонімні функції часто передаються як аргументи до інших функцій (наприклад, у методах
map
,filter
,forEach
).const numbers = [1, 2, 3]; const doubled = numbers.map(function (num) { return num * 2; }); console.log(doubled); // [2, 4, 6]
-
Функціональний вираз: Анонімна функція може бути присвоєна змінній.
const greet = function () { console.log("Hello"); }; greet(); // Hello
-
Самовиконувана функція (IIFE): Анонімна функція може бути негайно виконана.
(function () { console.log("I am an IIFE"); })();
-
У стрілкових функціях: Стрілкові функції — це синтаксично скорочений варіант анонімних функцій.
const add = (a, b) => a + b; console.log(add(2, 3)); // 5
-
Переваги анонімних функцій:
- Короткий синтаксис: Особливо у випадку однорядкових функцій.
- Локальність: Використовуються лише там, де потрібні, що сприяє чистоті коду.
-
Недоліки:
- Немає імені: Ускладнюється налагодження коду, оскільки у стеку викликів такі функції позначаються як
<anonymous>
. - Відсутність повторного використання: Не можна викликати повторно без збереження в змінну або передачі куди-небудь.
- Немає імені: Ускладнюється налагодження коду, оскільки у стеку викликів такі функції позначаються як
15. Що таке стрілкова функція і як вона відрізняється від звичайної функції?
-
Стрілкова функція (arrow function) — це скорочений синтаксис для оголошення функцій у JavaScript, введений в ES6. Вона має компактну форму і поводиться інакше, ніж звичайна функція, особливо щодо контексту
this
. -
Синтаксис:
const functionName = (param1, param2) => { // тіло функції return param1 + param2; };
-
Приклад однорядкової функції:
const add = (a, b) => a + b; // автоматично повертає результат console.log(add(2, 3)); // 5
-
Основні відмінності:
-
Контекст
this
:- У стрілкових функцій немає власного
this
. Вони успадковуютьthis
із зовнішнього оточення. - У звичайних функцій
this
залежить від способу виклику (динамічно прив'язується).
const obj = { value: 10, regularFunction: function () { console.log(this.value); // 10 }, arrowFunction: () => { console.log(this.value); // undefined (успадковує this із глобального контексту) }, }; obj.regularFunction(); obj.arrowFunction();
- У стрілкових функцій немає власного
-
Конструктор:
- Стрілкові функції не можуть використовуватися як конструктори.
- Виклик new зі стрілковою функцією викликає помилку.
const Arrow = () => {}; const Regular = function () {}; new Arrow(); // Помилка new Regular(); // Працює
-
Синтаксис:
- Стрілкова функція більш лаконічна, особливо для однорядкових операцій.
- Звичайна функція може мати більш розгорнутий вигляд, але є універсальною.
// Звичайна функція function multiply(a, b) { return a * b; } // Стрілкова функція const multiplyArrow = (a, b) => a * b;
-
arguments
:- У стрілкових функцій немає псевдомасиву
arguments
. Щоб отримати аргументи, слід використовувати оператор rest (...). - У звичайних функцій є доступ до
arguments
.
const regularFunc = function () { console.log(arguments); // Псевдомасив }; const arrowFunc = (...args) => { console.log(args); // Справжній масив }; regularFunc(1, 2, 3); arrowFunc(1, 2, 3);
- У стрілкових функцій немає псевдомасиву
-
Ключове слово
super
:- Стрілкові функції успадковують
super
із зовнішнього контексту. - У звичайних функцій
super
визначається залежно від їх виклику.
- Стрілкові функції успадковують
-
Коли використовувати:
- Стрілкові функції добре підходять для коротких виразів, обробників подій, методів масивів (
map
,filter
,reduce
), а також там, де важливе збереження контекстуthis
. - Звичайні функції варто використовувати для більш складних сценаріїв, що потребують власного
this
,arguments
або можливості виклику черезnew
.
- Стрілкові функції добре підходять для коротких виразів, обробників подій, методів масивів (
16. Які методи перебору масивів ви знаєте?
- Основні методи перебору масивів у JavaScript:
-
forEach
- Викликає передану функцію для кожного елемента масиву.
- Нічого не повертає (завжди undefined).
const arr = [1, 2, 3]; arr.forEach((num) => console.log(num)); // Виведе: 1, 2, 3
-
map
- Створює новий масив, застосовуючи передану функцію до кожного елемента.
- Не змінює вихідний масив.
const arr = [1, 2, 3]; const doubled = arr.map((num) => num * 2); console.log(doubled); // [2, 4, 6]
-
filter
- Створює новий масив із елементів, що відповідають умовам функції.
const arr = [1, 2, 3, 4]; const even = arr.filter((num) => num % 2 === 0); console.log(even); // [2, 4]
-
reduce
- Агрегує масив в одне значення, використовуючи функцію та початкове значення.
const arr = [1, 2, 3]; const sum = arr.reduce((acc, num) => acc + num, 0); console.log(sum); // 6
-
some
- Повертає true, якщо хоч один елемент відповідає умові.
const arr = [1, 2, 3]; console.log(arr.some((num) => num > 2)); // true
-
every
- Повертає true, якщо всі елементи відповідають умові.
const arr = [2, 4, 6]; console.log(arr.every((num) => num % 2 === 0)); // true
-
find
- Повертає перший елемент, що відповідає умові, або undefined.
const arr = [1, 2, 3]; console.log(arr.find((num) => num > 1)); // 2
-
findIndex
- Повертає індекс першого елемента, що відповідає умові, або -1.
const arr = [1, 2, 3]; console.log(arr.findIndex((num) => num > 1)); // 1
-
flatMap
- Поєднує функціональність map і flat. Повертає плоский масив.
const arr = [1, 2, 3]; console.log(arr.flatMap((num) => [num, num * 2])); // [1, 2, 2, 4, 3, 6]
-
keys
,values
,entries
- keys: ітератор ключів (індексів).
- values: ітератор значень.
- entries: ітератор пар [індекс, значення].
const arr = ["a", "b", "c"]; for (let key of arr.keys()) console.log(key); // 0, 1, 2 for (let value of arr.values()) console.log(value); // 'a', 'b', 'c' for (let [index, value] of arr.entries()) console.log(index, value); // 0 'a', 1 'b', 2 'c'
-
for...of
- Простий синтаксис для ітерації масивів.
const arr = [1, 2, 3]; for (const num of arr) console.log(num); // Виведе: 1, 2, 3
-
sort
- Сортує масив на місці.
const arr = [3, 1, 2]; arr.sort((a, b) => a - b); console.log(arr); // [1, 2, 3]
-
reverse
- Перевертає порядок елементів у масиві.
const arr = [1, 2, 3]; arr.reverse(); console.log(arr); // [3, 2, 1]
-
slice
- Повертає копію частини масиву.
const arr = [1, 2, 3]; const subArr = arr.slice(1); console.log(subArr); // [2, 3]
-
splice
- Додає, видаляє або замінює елементи в масиві.
const arr = [1, 2, 3]; arr.splice(1, 1, 4); // Видаляє 1 елемент із позиції 1, додає 4 console.log(arr); // [1, 4, 3]
- Вибір методу залежить від задачі:
- Для фільтрації:
filter
. - Для перетворення:
map
. - Для пошуку:
find
/findIndex
. - Для ітерації:
forEach
/for...of
.
- Для фільтрації:
17. Що таке JSON і як працювати з ним у JavaScript?
-
JSON (JavaScript Object Notation) — це текстовий формат обміну даними, що легко читається як людиною, так і комп'ютером. Його використовують для передачі даних між клієнтом і сервером. Формат базується на синтаксисі об'єктів JavaScript, але підтримується в багатьох мовах програмування.
-
Основні особливості JSON:
-
Ключі:
- Завжди рядки.
- Беруться в подвійні лапки ("").
-
Значення:
- Можуть бути: рядками, числами, логічними значеннями, масивами, об'єктами, null.
- Не підтримує функції, undefined, NaN.
-
Приклад JSON:
{ "name": "Alice", "age": 25, "isStudent": false, "courses": ["Math", "Physics"], "address": { "city": "Kyiv", "zip": "01001" } }
-
Як працювати з JSON у JavaScript?
-
Перетворення об'єкта у JSON (
JSON.stringify
):- Використовується для перетворення JavaScript-об'єкта в JSON-рядок.
const user = { name: "Alice", age: 25, isStudent: false, }; const jsonString = JSON.stringify(user); console.log(jsonString); // Виведе: '{"name":"Alice","age":25,"isStudent":false}'
-
Перетворення JSON у об'єкт (
JSON.parse
):- Використовується для перетворення JSON-рядка у JavaScript-об'єкт.
const jsonString = '{"name":"Alice","age":25,"isStudent":false}'; const user = JSON.parse(jsonString); console.log(user); // Виведе: { name: 'Alice', age: 25, isStudent: false }
-
Робота з сервером:
Передача даних у форматі JSON:
-
Надсилання даних:
- Використовуйте fetch із JSON.stringify для передачі JSON.
const data = { name: "Alice", age: 25 }; fetch("https://example.com/api", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), });
-
Отримання даних:
- Використовуйте fetch із JSON.parse для обробки відповіді.
fetch("https://example.com/api") .then((response) => response.json()) .then((data) => console.log(data));
- Типові помилки:
-
Неправильний формат JSON:
const invalidJson = "{ name: 'Alice' }"; // Помилка: ключі та рядки без подвійних лапок JSON.parse(invalidJson); // Викине помилку
-
Перетворення циклічного об'єкта:
const obj = {}; obj.self = obj; JSON.stringify(obj); // Викине помилку: Converting circular structure to JSON
-
Застосування JSON:
- Обмін даними між клієнтом і сервером.
- Збереження налаштувань у файлах чи локальному сховищі.
- API для роботи з веб-сервісами.
18. Як виконується асинхронний код у JavaScript?
-
Асинхронний код у JavaScript виконується за допомогою подій, колбеків, промісів і
async/await
. Виконання базується на подійному циклі (Event Loop), що дозволяє обробляти асинхронні задачі поза основним потоком виконання. -
Механізми асинхронного виконання:
- Події та Колбеки
-
Код виконується, коли завершується асинхронна операція (наприклад, таймер, запит до сервера).
-
Колбек-функції викликаються після завершення операції.
setTimeout(() => { console.log("Асинхронно через 1 секунду"); }, 1000); console.log("Цей код виконається першим"); // Виведе: // Цей код виконається першим // Асинхронно через 1 секунду
-
Проміси (
Promises
)Promise
представляє операцію, яка виконується асинхронно та може завершитися успішно або з помилкою.- Має методи
.then
і.catch
для обробки результату.
const promise = new Promise((resolve, reject) => { setTimeout(() => resolve("Дані отримано"), 1000); }); promise .then((data) => console.log(data)) // Виведе: Дані отримано .catch((err) => console.error(err));
-
async/await
- Синтаксичний цукор для роботи з промісами.
- Дозволяє писати асинхронний код так, ніби він синхронний.
const fetchData = async () => { try { const response = await fetch( "https://jsonplaceholder.typicode.com/posts/1" ); const data = await response.json(); console.log(data); } catch (error) { console.error("Помилка:", error); } }; fetchData();
- Ключові поняття:
- Event Loop (Цикл подій):
-
Основний механізм, що дозволяє виконувати асинхронний код.
-
Розподіляє задачі між:
- Call Stack (стек викликів): виконує синхронний код.
- Task Queue (черга задач): для колбеків від
setTimeout
, DOM-подій. - Microtask Queue: для промісів та
async/await
.
- Microtasks vs. Macrotasks:
-
Microtasks (вищий пріоритет): Promise.then, MutationObserver.
-
Macrotasks: setTimeout, setInterval, I/O, події DOM.
console.log("Початок"); setTimeout(() => console.log("Macrotask"), 0); Promise.resolve().then(() => console.log("Microtask")); console.log("Кінець"); // Виведе: // Початок // Кінець // Microtask // Macrotask
-
Приклади:
-
Асинхронний ланцюжок:
fetch("https://jsonplaceholder.typicode.com/posts/1") .then((response) => response.json()) .then((data) => console.log(data)) .catch((err) => console.error("Помилка:", err));
-
Паралельне виконання:
const promise1 = fetch("https://jsonplaceholder.typicode.com/posts/1"); const promise2 = fetch("https://jsonplaceholder.typicode.com/posts/2"); Promise.all([promise1, promise2]) .then((responses) => Promise.all(responses.map((r) => r.json()))) .then((data) => console.log(data));
Асинхронний код дозволяє виконувати тривалі операції без блокування головного потоку.
19. Що таке Event Loop (Цикл подій)?
- Event Loop — це механізм в JavaScript, який відповідає за обробку асинхронних операцій.
- Він працює так:
- Call Stack (Стек викликів): Зберігає функції, які виконуються.
- Task Queue (Черга завдань): Містить асинхронні колбеки (наприклад, setTimeout), готові до виконання.
- Microtask Queue (Черга мікрозавдань): Містить мікрозавдання, як-от Promise або MutationObserver.
-
Процес:
-
Якщо Call Stack порожній, Event Loop бере завдання з Microtask Queue (пріоритетно) або Task Queue й переміщує їх у Call Stack для виконання.
20. Що таке Call Stack (Стек викликів)?
-
Call Stack — це структура даних, яка працює за принципом LIFO (Last In, First Out) і використовується для відстеження виконання функцій у JavaScript.
- Коли викликається функція, вона додається до вершини стеку.
- Коли функція завершується, вона видаляється зі стеку.
- Якщо функція викликає іншу функцію, та додається до стеку поверх попередньої.
-
Call Stack обробляє тільки синхронний код. Якщо стек переповнюється (наприклад, через рекурсію без базового випадку), це спричиняє помилку RangeError:
Maximum call stack size exceeded
.
21. Що таке Task Queue (Черга завдань)?
-
Task Queue — це черга, яка зберігає асинхронні завдання, готові до виконання, наприклад, колбеки з
setTimeout
,setInterval
, або події DOM. -
Коли Call Stack порожній, Event Loop бере завдання з Task Queue і додає його до стеку викликів для виконання.
-
Task Queue має нижчий пріоритет порівняно з Microtask Queue, тому мікрозавдання (наприклад, з
Promises
) обробляються першими, навіть якщо в Task Queue вже є готові завдання.
22. Що таке Microtask Queue (Черга мікрозавдань)?
-
Microtask Queue — це черга для завдань з високим пріоритетом, наприклад:
- Колбеки з
Promise
(наприклад,.then
,.catch
,.finally
). - Завдання з
MutationObserver
.
- Колбеки з
-
Після виконання кожної операції в Call Stack, Event Loop перевіряє Microtask Queue і виконує всі мікрозавдання, перш ніж перейти до Task Queue.
-
Це забезпечує швидку обробку мікрозавдань і робить їх пріоритетними над звичайними асинхронними завданнями.
23. Як ви працюєте з асинхронним кодом у JavaScript без використання async/await? Які інші підходи ви розглядаєте для роботи з асинхронністю?
- Без
async/await
асинхронний код у JavaScript можна обробляти такими підходами:
-
Callbacks (Колбеки):
-
Передача функції як аргумент для обробки результату.
-
Мінус: створює "callback hell", ускладнюючи читабельність.
setTimeout(() => { console.log("Дані завантажені"); }, 1000);
-
-
Promises:
-
Використання then, catch, finally для обробки асинхронності.
-
Більш читабельний, ніж колбеки, але може бути громіздким для складних сценаріїв.
Копіювати код fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));
-
-
Event Listeners (Слухачі подій):
-
Реагування на асинхронні події через обробники, наприклад, addEventListener.
-
Використовується для роботи з DOM чи подіями введення користувача.
button.addEventListener("click", () => { console.log("Кнопка натиснута"); });
-
-
RxJS (Reactive Extensions):
-
Використання бібліотеки для роботи з потоками даних через об'єкти Observable.
-
Підходить для складних асинхронних сценаріїв, як-от обробка кількох подій одночасно.
const observable = from(fetch("/api/data")); observable.subscribe({ next: (response) => console.log(response), error: (err) => console.error(err), });
-
24. Яка різниця між операторами порівняння == і ===?
- В JavaScript == і === відрізняються способом порівняння:
-
== (Нестроге порівняння):
- Виконує приведення типів (type coercion), тому значення можуть бути різних типів.
"5" == 5; // true false == 0; // true null == undefined; // true
-
=== (Строге порівняння): Порівнює без приведення типів. Значення повинні бути одного типу.
"5" === 5; // false false === 0; // false null === undefined; // false
-
Коротко:
- Використовуйте ===, щоб уникнути неочікуваних результатів через приведення типів.
- == підходить лише у випадках, коли ви точно розумієте, як працює приведення.
25. Що таке прототип у JavaScript?
-
Прототип у JavaScript — це механізм, за допомогою якого об'єкти можуть успадковувати властивості та методи від інших об'єктів.
-
Як це працює:
-
Кожен об'єкт має внутрішнє посилання на свій прототип, яке називається
[[Prototype]]
. -
Прототипом об'єкта може бути інший об'єкт або
null
. -
Коли ви намагаєтесь отримати доступ до властивості або методу об'єкта, JavaScript шукає їх у цьому об'єкті. Якщо не знаходить, переходить до прототипу й так далі в ланцюжку прототипів (prototype chain).
-
Приклад:
function Person(name) { this.name = name; } Person.prototype.greet = function () { console.log(`Привіт, я ${this.name}`); }; const user = new Person("Іван"); user.greet(); // Привіт, я Іван
Person.prototype
— це прототип для всіх об'єктів, створених черезPerson
.- Метод
greet
доступний об'єктуuser
через його прототип.
-
Прототипне наслідування:
const animal = { eat() { console.log("Їм"); }, }; const dog = Object.create(animal); dog.bark = function () { console.log("Гав!"); }; dog.eat(); // Їм (успадковано з animal) dog.bark(); // Гав!
-
Ключові моменти:
- Прототипи — це основа роботи з об'єктами у JavaScript.
- Ланцюжок прототипів завершується
null
. Object.getPrototypeOf(obj)
дозволяє отримати прототип об'єкта.
26. У чому різниця між null та undefined?
null
іundefined
— це два різні типи даних в JavaScript, які обидва означають "відсутність значення", але вони використовуються в різних контекстах.
-
null
:-
Це спеціальний об'єкт у JavaScript, що означає "відсутність значення" або "порожній об'єкт".
-
Його зазвичай використовують, щоб явно вказати на відсутність значення або на відсутність об'єкта.
-
Ініціалізується вручну.
let user = null; // явно вказано, що значення відсутнє
-
-
undefined
:- Це примітивний тип в JavaScript, що означає, що змінна була оголошена, але їй не було присвоєно значення.
- Змінні без значення автоматично мають тип undefined.
- Також використовується як значення за умовчанням для неініціалізованих параметрів функцій.
let user; console.log(user); // undefined function test(a) { console.log(a); // undefined, якщо параметр не передано } test();
-
Основні відмінності:
- null — це об'єкт, явно призначений для вказівки на відсутність значення.
- undefined — це значення, яке присвоюється змінній, коли їй не було надано значення або коли параметр функції не переданий.
-
Порівняння:
- null == undefined — true (при порівнянні з == вони вважаються рівними через приведення типів).
- null === undefined — false (при строгому порівнянні вони не однакові, бо мають різні типи).
27. Що таке контекст? Як можна змінювати контекст виконання функції?
-
Контекст виконання (execution context) — це середовище, в якому виконується JavaScript-код. Контекст визначає, які змінні, функції та об'єкти доступні в процесі виконання.
-
Існує кілька видів контексту:
-
Глобальний контекст: Це початковий контекст, в якому запускається код (в браузері — це глобальний об'єкт window).
-
Контекст функції: Кожен виклик функції створює новий контекст виконання, що дозволяє доступ до змінних і параметрів функції.
-
Контекст об'єкта: Коли функція викликається як метод об'єкта, контекстом є цей об'єкт.
- Як змінювати контекст виконання функції?
-
this
— це ключовий елемент контексту. Він вказує на об'єкт, що є контекстом виконання. -
Методи для зміни контексту:
call()
: Викликає функцію з конкретним контекстом.
function greet() { console.log(`Привіт, ${this.name}`); } const person = { name: "Іван" }; greet.call(person); // Привіт, Іван
apply()
: Теж викликає функцію з певним контекстом, але аргументи передаються у вигляді масиву.
function sum(a, b) { console.log(this.name, a + b); } const person = { name: "Оля" }; sum.apply(person, [2, 3]); // Оля 5
bind()
: Створює нову функцію з прив'язаним контекстом, яку можна викликати пізніше.
function show() { console.log(this.name); } const person = { name: "Петро" }; const showPerson = show.bind(person); showPerson(); // Петро
-
Пояснення:
call()
таapply()
викликають функцію одразу з визначеним контекстом.bind()
створює нову функцію, яка завжди має певний контекст, що може бути викликана пізніше.
Зміна контексту важлива, коли потрібно працювати з методами, які викликаються в різних обставинах, або при роботі з колбеками та асинхронним кодом.
28. Що таке Promise? У яких випадках ви ним користуєтеся?
-
Promise
— це об'єкт, який представляє результат асинхронної операції, яка може бути завершена або з успіхом, або з помилкою. Promise дозволяє працювати з асинхронним кодом більш зручним способом, ніж через колбеки. -
Структура:
- Pending — стан, коли операція ще не завершена.
- Resolved (Fulfilled) — стан, коли операція успішно завершена.
- Rejected — стан, коли операція завершена з помилкою.
-
Приклад створення:
let promise = new Promise((resolve, reject) => { let success = true; if (success) { resolve("Операція успішна"); } else { reject("Щось пішло не так"); } }); promise .then((result) => console.log(result)) // Обробка успіху .catch((error) => console.log(error)); // Обробка помилки
-
Переваги:
- Читабельність: Ланцюжок
.then()
дозволяє більш зручно обробляти асинхронні операції. - Помилки: Легше обробляти помилки через
.catch()
. - Кілька операцій: Легко працювати з кількома асинхронними задачами одночасно через
Promise.all()
абоPromise.race()
.
- Читабельність: Ланцюжок
Promise робить асинхронний код більш структурованим і менш громіздким порівняно з використанням колбеків.
29. Які особливості об’єктноорієнтованого програмування у JavaScript?
- Об'єктноорієнтоване програмування (ООП) у JavaScript має кілька особливостей, оскільки мова не є класично об'єктноорієнтованою, як, наприклад, Java або C#. Однак вона підтримує об'єктноорієнтовані концепції через механізм прототипів і з введенням класів у
ES6
. Ось основні особливості ООП у JavaScript:
-
Прототипне наслідування (Prototype-based Inheritance):
-
JavaScript використовує прототипне наслідування, а не класове. Кожен об'єкт може мати прототип, який є іншим об'єктом, і успадковує від нього властивості та методи.
-
Коли ви звертаєтеся до властивості об'єкта, JavaScript спочатку шукає її в самому об'єкті, а потім переходить до його прототипу.
const person = { name: "Іван", greet() { console.log(`Привіт, я ${this.name}`); }, }; const user = Object.create(person); user.name = "Оля"; user.greet(); // Привіт, я Оля
-
-
Функції як конструктори:
- У JavaScript функції можуть бути використані як конструктори об'єктів. Це дозволяє створювати екземпляри об'єктів із певними властивостями та методами.
function Person(name, age) { this.name = name; this.age = age; } const user = new Person("Іван", 25); console.log(user.name); // Іван
-
Класи (ES6+ класова синтаксична конструкція):
- З введенням
ES6
, JavaScript отримав класову синтаксис для створення об'єктів. Це полегшує створення класів і працює на основі прототипного наслідування.
class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { console.log(`Привіт, я ${this.name}`); } } const user = new Person("Іван", 25); user.greet(); // Привіт, я Іван
- З введенням
-
Методи та властивості:
- Об'єкти можуть мати методи (функції, прив'язані до об'єктів) та властивості (дані).
- Методи можуть бути визначені за допомогою класів або функцій-конструкторів.
const person = { name: "Іван", greet() { console.log(`Привіт, я ${this.name}`); }, }; person.greet(); // Привіт, я Іван
-
Інкапсуляція:
- У JavaScript є можливість інкапсулювати дані, використовуючи закриті або приватні властивості за допомогою замикань. З
ES2022
також з'явилася підтримка приватних полів у класах через#
.
class Person { #name; constructor(name) { this.#name = name; } getName() { return this.#name; } } const person = new Person("Іван"); console.log(person.getName()); // Іван
- У JavaScript є можливість інкапсулювати дані, використовуючи закриті або приватні властивості за допомогою замикань. З
-
Поліморфізм:
- JavaScript підтримує поліморфізм через перезапис методів. Це означає, що різні об'єкти можуть мати однакові методи, але з різною реалізацією.
class Animal { speak() { console.log("Робить звук"); } } class Dog extends Animal { speak() { console.log("Гав!"); } } const dog = new Dog(); dog.speak(); // Гав!
-
Абстракція:
- Абстракція в JavaScript реалізується через класові та функціональні методи, що дозволяє приховувати складність реалізації і зберігати лише важливу інформацію для користувача.
- Абстракція може бути досягнута через інтерфейси або базові класи, хоча JavaScript не має явної підтримки інтерфейсів, як в інших мовах.
-
Метод new:
- Ключове слово
new
використовується для створення екземплярів класів чи функцій-конструкторів, що ініціалізує новий об'єкт і встановлює прототип.
Копіювати код function Person(name) { this.name = name; } const person = new Person('Іван');
- Ключове слово
-
Підсумок:
- Прототипне наслідування замість класичного.
- Функції-конструктори для створення об'єктів.
- ES6 класи спрощують синтаксис для створення об'єктів та наслідування.
- Можливість реалізації інкапсуляції та поліморфізму.
- Абстракція через методи класів та замикання.
JavaScript поєднує елементи класичного ООП з прототипним підходом, що дозволяє використовувати різні стилі програмування в залежності від задачі.
30. Як з JS-коду звернутись до HTML-елемента та змінити його текст?
-
Щоб звернутися до HTML-елемента та змінити його текст у JavaScript, можна використовувати різні методи доступу до елементів DOM.
-
Приклад:
- Використовуємо getElementById(), querySelector() або інші методи для доступу до елемента.
- Змінюємо текст елемента за допомогою властивості textContent або innerText.
-
Приклад з
getElementById():
<!DOCTYPE html> <html lang="uk"> <head> <meta charset="UTF-8" /> <title>Зміна тексту</title> </head> <body> <p id="example">Старий текст</p> <script> // Отримуємо елемент за ID const element = document.getElementById("example"); // Змінюємо текст element.textContent = "Новий текст"; </script> </body> </html>
-
Приклад з
querySelector():
<!DOCTYPE html> <html lang="uk"> <head> <meta charset="UTF-8" /> <title>Зміна тексту</title> </head> <body> <p class="example">Старий текст</p> <script> // Отримуємо елемент за класом const element = document.querySelector(".example"); // Змінюємо текст element.textContent = "Новий текст"; </script> </body> </html>
-
Різниця між
textContent
іinnerText
:-
textContent:
Оновлює текст у елементі, включаючи прихований текст, але не виконує рендеринг CSS. -
innerText:
Оновлює текст, враховуючи стилі CSS (наприклад, схований текст не буде видимим).
-
Обидва підходи працюють для зміни тексту, але textContent — це більш швидкий і загальний спосіб.
31. Що таке деструктуризація?
- Деструктуризація в JavaScript — це синтаксис, який дозволяє розпаковувати значення з масивів або властивості з об'єктів у окремі змінні. Це скорочує код і робить його більш зрозумілим.
- Деструктуризація масивів
-
Розпаковує значення елементів масиву в окремі змінні за позицією.
-
Приклад:
const numbers = [10, 20, 30]; const [a, b, c] = numbers; console.log(a); // 10 console.log(b); // 20 console.log(c); // 30
- Деструктуризація об'єктів
-
Розпаковує значення властивостей об'єкта в змінні за іменами ключів.
-
Приклад:
const user = { name: "Evan", age: 25 }; const { name, age } = user; console.log(name); // Evan console.log(age); // 25
- Деструктуризація в функціях
-
Дозволяє передавати об'єкти або масиви у функцію і розпаковувати їх прямо в параметрах.
- Масиви:
function sum([a, b]) { return a + b; } console.log(sum([10, 20])); // 30
- Об'єкти:
function greet({ name, age }) { console.log(`Привіт, ${name}, тобі ${age} років.`); } greet({ name: "Evan", age: 25 });
-
Переваги:
- Зменшує кількість коду.
- Полегшує роботу з вкладеними структурами.
- Підвищує читабельність.
-
Деструктуризація — це потужний інструмент, який широко використовується у сучасному JavaScript.
32. Що буде, якщо звернутись до елемента масива, якого немає за індексом?
-
Якщо звернутися до елемента масиву за індексом, якого не існує, JavaScript поверне
undefined
. -
Причина:
- У JavaScript масиви є об'єктами, і доступ до елементів масиву працює через властивості об'єкта. Якщо властивість (тобто індекс) не існує, результатом буде
undefined
.
- У JavaScript масиви є об'єктами, і доступ до елементів масиву працює через властивості об'єкта. Якщо властивість (тобто індекс) не існує, результатом буде
33. У чому різниця між for..of та for...in?
for...of
іfor...in
використовуються для ітерації, але мають різне призначення та працюють з різними типами даних.
- for...of
-
Ітерує значення ітерабельних об'єктів, таких як масиви, рядки, об'єкти типу
Map
,Set
, або об'єкти з реалізованим методомSymbol.iterator
.- Приклад:
const array = ["a", "b", "c"]; for (const value of array) { console.log(value); // Виведе: 'a', 'b', 'c' }
-
Особливості:
- Підходить для роботи з масивами та іншими ітерабельними об'єктами.
- Використовує значення елементів.
- Не підходить для ітерації по об'єктах з властивостями.
- for...in
-
Ітерує ключі (властивості) об'єкта або індекси масиву.
- Приклад з об'єктом:
const obj = { name: "Іван", age: 25 }; for (const key in obj) { console.log(key); // Виведе: 'name', 'age' }
- Приклад з масивом:
const array = ["a", "b", "c"]; for (const index in array) { console.log(index); // Виведе: '0', '1', '2' }
-
Особливості:
- Використовується для ітерації по об'єктах.
- Повертає ключі об'єкта або індекси масиву як рядки.
- Не рекомендується для масивів, оскільки включає властивості прототипу.
-
Висновок:
for...of
: Використовуйте для роботи з масивами та іншими ітерабельними об'єктами.for...in
: Використовуйте для ітерації по властивостях об'єкта. Не підходить для масивів.
34. Навіщо використовується оператор &&?
-
Оператор
&&
(логічне І) в JavaScript використовується для перевірки логічних умов і короткого замикання. Його основне призначення — повертати перше хибне значення або останнє істинне. -
Основні випадки використання:
-
Перевірка кількох умов:
- Повертає true, якщо всі операнди істинні.
- Якщо хоча б один операнд хибний, повертає цей операнд.
const a = true; const b = false; console.log(a && b); // false console.log(a && true); // true
-
Коротке замикання:
- Якщо перший операнд хибний, далі умови не перевіряються, і повертається його значення.
- Якщо перший операнд істинний, обчислюється і повертається другий.
const result = false && console.log("Не виконається"); // false const value = true && "Результат"; // 'Результат'
-
Умовне виконання коду:
- Використовується для виклику функцій або виконання дій лише при істинності умови.
const user = { loggedIn: true }; user.loggedIn && console.log("Користувач увійшов"); // 'Користувач увійшов'
-
Використання в присвоєнні значень:
- Якщо перший операнд істинний, результатом буде другий.
const value = true && "Hello"; // 'Hello' const empty = false && "World"; // false
-
Повернення значень:
-
&& не просто повертає true або false. Він повертає значення одного з операндів.
-
Працює з будь-якими типами, не лише з булевими.
-
Приклад:
console.log("a" && "b"); // 'b' (останнє істинне значення) console.log(false && "b"); // false (перше хибне значення) console.log("a" && 0); // 0 (перше хибне значення)
-
-
Висновок:
-
Оператор && корисний для:
- Перевірки складених умов.
- Зупинки виконання при хибному значенні (коротке замикання).
- Умовного виконання виразів.
-
35. Навіщо використовується оператор ||?
-
Оператор
||
(логічне АБО) в JavaScript використовується для перевірки логічних умов і короткого замикання. Його основна мета — повертати перше істинне значення або останнє хибне. -
Основні випадки використання:
-
Перевірка кількох умов:
- Повертає true, якщо хоча б один операнд істинний.
- Якщо всі операнди хибні, повертає останнє хибне значення.
const a = true; const b = false; console.log(a || b); // true console.log(b || false); // false
-
Коротке замикання:
- Якщо перший операнд істинний, далі умови не перевіряються, і повертається його значення.
- Якщо перший операнд хибний, обчислюється і повертається другий.
const result = true || console.log("Не виконається"); // true const value = false || "Результат"; // 'Результат'
-
Значення за замовчуванням:
- Використовується для задання дефолтного значення, якщо перше значення хибне.
const userName = "" || "Анонім"; // 'Анонім' const number = 0 || 42; // 42
-
Умовне виконання коду:
- Логічне АБО дозволяє виконати альтернативну дію, якщо перша умова не спрацювала.
const isAuthorized = false; isAuthorized || console.log("Доступ заборонено"); // 'Доступ заборонено'
-
Повернення значень:
-
|| не обмежується булевими значеннями. Він повертає перше істинне значення або останнє хибне.
-
Приклади:
console.log("a" || "b"); // 'a' (перше істинне) console.log(false || "b"); // 'b' (перше істинне) console.log(null || undefined || 0); // 0 (останнє хибне)
-
-
Висновок:
-
Оператор || корисний для:
- Перевірки чи хоча б одна умова виконується.
- Встановлення значень за замовчуванням.
- Короткого замикання для оптимізації виконання коду.
-
36. Навіщо використовується оператор !!?
-
Оператор
!!
у JavaScript використовується для перетворення будь-якого значення в його булевий еквівалент. Це простий спосіб привести значення доtrue
абоfalse
. -
Як працює:
- Перший
!
: Інвертує значення. Перетворює його на булеве, якщо це ще не було зроблено, і змінює на протилежне (істинне → хибне, хибне → істинне). - Другий
!
: Знову інвертує значення, повертаючи початкову логіку, але вже у булевій формі.
-
Приклади:
- Приведення до булевого типу:
console.log(!!0); // false (0 вважається "хибним") console.log(!!1); // true (1 вважається "істинним") console.log(!!""); // false (порожній рядок — "хибний") console.log(!!"hello"); // true (непорожній рядок — "істинний") console.log(!!null); // false console.log(!!undefined); // false console.log(!!{}); // true (об'єкти завжди "істинні") console.log(!![]); // true (масиви завжди "істинні")
-
Для чого використовується:
-
Приведення до булевого типу:
- Використовується для явного переведення значення в булевий тип в умовах або перевірках.
const isActive = !!someVariable;
-
Перевірка істинності значення:
- Зручно для перевірки, чи значення існує або чи є воно "істинним".
if (!!userName) { console.log("Ім'я користувача задано"); }
-
Явна демонстрація булевого результату:
- Використовується, коли важливо явно показати, чи значення є істинним або хибним.
const isValid = !!(age >= 18); // true, якщо вік >= 18
-
Висновок:
- Оператор
!!
ефективно перетворює будь-яке значення у булеве. Це зручний інструмент для перевірок, умов та обробки даних у коді.
- Оператор
37. Навіщо використовується оператор !?
-
Оператор
!
(логічне НЕ) у JavaScript використовується для інверсії булевого значення. Він змінює істинне значення на хибне і навпаки. -
Основні випадки використання:
- Інверсія булевого значення:
-
Оператор
!
змінює логіку булевого виразу.console.log(!true); // false console.log(!false); // true
- Перетворення в булевий тип:
-
Якщо значення не є булевим, оператор
!
автоматично приводить його до булевого типу, а потім інвертує.console.log(!0); // true (0 вважається "хибним") console.log(!"hello"); // false (рядок вважається "істинним") console.log(!undefined); // true
- Умовні перевірки:
-
Використовується для перевірки хибності значення.
const isValid = false; if (!isValid) { console.log("Не валідно"); }
- Зворотна логіка:
-
Полегшує написання умов, які мають бути виконані при хибних значеннях.
const user = null; if (!user) { console.log("Користувач не знайдений"); }
-
Приклади з інверсією:
- Інверсія:
const isOnline = false; console.log(!isOnline); // true (зворотне значення)
- Вкладені перевірки:
const isEmpty = !array.length; // true, якщо масив порожній
-
Висновок:
- Оператор
!
інвертує булеве значення та дозволяє зручно перевіряти хибність або істинність умов. Це базовий інструмент для роботи з логічними виразами.
- Оператор
38. Які значення в JS є хибними?
-
У JavaScript до хибних значень (falsy values) належать ті, що при приведенні до булевого типу стають
false
. -
Перелік хибних значень:
false
— логічне значення "хибність".0
— числовий нуль.-0
— від'ємний нуль (рідко використовується, але технічно існує).NaN
— "не число".""
— порожній рядок (подвійні лапки).''
— порожній рядок (одинарні лапки).(``)
— порожній рядок (шаблонні літерали).null
— відсутність значення.undefined
— невизначене значення.
-
Приклади:
console.log(Boolean(false)); // false console.log(Boolean(0)); // false console.log(Boolean("")); // false console.log(Boolean(null)); // false console.log(Boolean(undefined)); // false console.log(Boolean(NaN)); // false
39. Які значення в JS є правдивими?
-
У JavaScript
правдиві значення (truthy values)
— це ті, які при приведенні до булевого типу стаютьtrue
. Це всі значення, які не входять до списку хибних (falsy values). -
Перелік типових правдивих значень:
-
Непорожні рядки:
console.log(Boolean("hello")); // true console.log(Boolean(" ")); // true (навіть якщо це пробіл) console.log(Boolean("0")); // true
-
Числа, крім 0:
console.log(Boolean(42)); // true console.log(Boolean(-42)); // true console.log(Boolean(Infinity)); // true console.log(Boolean(-Infinity)); // true
-
Об'єкти (включаючи порожні):
console.log(Boolean({})); // true console.log(Boolean([])); // true
-
Функції:
console.log(Boolean(function () {})); // true
-
Спеціальні значення:
Symbol()
— завжди істинний.- Будь-який
BigInt
, відмінний від0n
.
40. Як перевірити, чи є значення хибним?
- Щоб перевірити, чи є
значення хибним (falsy)
у JavaScript, можна скористатися приведенням до булевого типу. Ось кілька способів:
-
Використання
!
(логічного НЕ):if (!value) { console.log("Значення є хибним"); }
- Логічне НЕ інвертує булеве значення, і для хибного результату умова виконається.
-
Використання
Boolean()
:if (!Boolean(value)) { console.log("Значення є хибним"); }
- Функція Boolean() явно перетворює значення в булеве. Якщо Boolean(value) повертає false, значення хибне.
-
Перевірка через подвійний
!!
:console.log(!!value); // true для правдивих, false для хибних
- Подвійний ! використовується для явного приведення значення до булевого типу. Якщо результат false, значення хибне.
-
Список хибних значень:
- Можна порівняти значення з відомими falsy values:
if ( value === false || value === 0 || value === "" || value === null || value === undefined || Number.isNaN(value) ) { console.log("Значення є хибним"); }
-
Приклади:
console.log(!0); // true (0 є хибним) console.log(!""); // true (порожній рядок є хибним) console.log(!undefined); // true (undefined є хибним) console.log(!42); // false (число 42 є правдивим) console.log(![]); // false (масив є правдивим)
-
Висновок:
- Найзручніший спосіб перевірити, чи значення хибне — використати !value.
41. Що таке DOM?
-
DOM (Document Object Model) — це програмний інтерфейс для веб-документів, який надає структуру HTML або XML документа у вигляді дерева об'єктів. DOM дозволяє програмам та скриптам взаємодіяти з документами, змінюючи їх вміст, структуру та стиль.
-
Основні моменти:
-
Представлення документа: DOM представляє HTML або XML документ як дерево елементів, де кожен вузол дерева є об'єктом, що відповідає певній частині документа (наприклад, тегу, атрибуту або тексту).
-
Динамічна взаємодія: Через DOM можна змінювати веб-сторінки на льоту. За допомогою JavaScript можна додавати, видаляти або змінювати елементи HTML, обробляти події (кліки, введення даних) та змінювати стиль елементів.
-
Структура дерева: DOM є деревом з кореневим елементом
<html>
, що містить елементи<head>
та<body>
, а ті, у свою чергу, містять інші елементи (наприклад,<div>
,<p>
,<span>
).
- Висновок:
- DOM є ключовим механізмом для взаємодії з веб-сторінками. Він дозволяє програмно змінювати структуру і зміст HTML-документів, що робить веб-сторінки динамічними та інтерактивними.
42. Що таке розповсюдження події (Event Propogation)?
- Розповсюдження події (Event Propagation) в JavaScript — це процес, за якого подія, що сталася на одному елементі, передається іншим елементам в DOM-дереві. Розповсюдження події можна розділити на два основні етапи:
-
Фаза захоплення (Capturing phase):
- Це перша фаза, коли подія "захоплюється" від кореня документа і йде вниз через усі батьківські елементи до того елемента, на якому була ініційована подія. Цей етап рідко використовується.
-
Фаза цільового елемента (Target phase):
- Це етап, коли подія потрапляє безпосередньо на елемент, на якому вона була ініційована (наприклад, натискання на кнопку). Тепер подія обробляється саме на цьому елементі.
-
Фаза спливання (Bubbling phase):
- Після обробки на цільовому елементі подія "спливає" (bubbles) до батьківських елементів і вище, поки не досягне кореня документа. Це основний етап, який найчастіше використовується для обробки подій.
-
Висновок:
- Розповсюдження події дозволяє ефективно управляти тим, як подія поширюється по DOM-дереву. Ви можете використовувати фазу захоплення, цільову фазу або спливання для обробки подій, а також контролювати це за допомогою методів
stopPropagation()
іstopImmediatePropagation()
.
- Розповсюдження події дозволяє ефективно управляти тим, як подія поширюється по DOM-дереву. Ви можете використовувати фазу захоплення, цільову фазу або спливання для обробки подій, а також контролювати це за допомогою методів
43. Чому результат порівняння двох схожих об'єктів є false?
-
У JavaScript результат порівняння двох схожих об'єктів за допомогою оператора
==
або===
зазвичай єfalse
, навіть якщо ці об'єкти виглядають схожими, через те, як працює порівняння об'єктів у JavaScript. -
Причина:
- Об'єкти в JavaScript порівнюються за посиланням, а не за їхнім вмістом. Тобто, коли ви порівнюєте два об'єкти, перевіряється чи вони вказують на один і той самий об'єкт в пам'яті, а не чи їхні властивості однакові.
-
Приклад:
const obj1 = { name: "John", age: 30 }; const obj2 = { name: "John", age: 30 }; onsole.log(obj1 == obj2); // false onsole.log(obj1 === obj2); // false
- Обидва об'єкти
obj1
таobj2
мають однакові властивості, але це різні об'єкти в пам'яті. Оператор==
та===
порівнюють посилання на об'єкти, тому результат порівняння будеfalse
.
- Обидва об'єкти
-
Пояснення:
==
— порівнює два значення, приводячи їх до спільного типу (для об'єктів це буде порівняння посилань).===
— порівнює два значення без приведення типів, тому також порівнює посилання для об'єктів.
-
Як порівняти об'єкти по вмісту?
- Якщо потрібно порівняти об'єкти за їхніми властивостями (по вмісту), вам слід вручну порівнювати кожну властивість або використати спеціальні методи, такі як
JSON.stringify()
:
console.log(JSON.stringify(obj1) === JSON.stringify(obj2)); // true
- Але зверніть увагу, що цей метод не працює для порівняння складніших об'єктів, таких як об'єкти з методами чи циклічні посилання.
- Якщо потрібно порівняти об'єкти за їхніми властивостями (по вмісту), вам слід вручну порівнювати кожну властивість або використати спеціальні методи, такі як
44. Який найшвидший спосіб перетворення рядка на число?
-
Найшвидший спосіб перетворення рядка на число в JavaScript — це використання унарного оператора +.
-
Приклад:
const str = "42"; const num = +str; console.log(num); // 42
-
Цей метод є дуже швидким і ефективним, оскільки він використовує внутрішнє перетворення типів JavaScript.
-
Альтернативи:
parseInt()
:
-
Перетворює рядок на ціле число.
const num = parseInt(str, 10); // 42
-
Однак це повільніше, ніж унарний оператор +, через додаткову обробку (встановлення бази для чисел).
parseFloat()
:
-
Перетворює рядок на число з плаваючою точкою.
const num = parseFloat(str); // 42
-
Також повільніше, ніж унарний оператор.
-
Висновок:
- Унарний оператор + є найшвидшим і найбільш ефективним способом перетворення рядка на число.
45. Як записати кілька виразів в один рядок?
-
Щоб записати кілька виразів в один рядок у JavaScript, можна використовувати крапку з комою
;
для розділення виразів. -
Приклад:
let a = 5; let b = 10; let c = a + b; console.log(c);
-
Тут ми об’єднали три вирази в одному рядку, розділивши їх крапками з комами.
-
Важливо:
- Використання крапок з комами дозволяє писати кілька інструкцій в одному рядку, але важливо не забувати про роздільники для уникнення помилок.
- Це не завжди є рекомендованим підходом, оскільки може погіршити читабельність коду, але в коротких ситуаціях це працює.
46. Що таке підняття (Hoisting)?
-
Підняття (Hoisting) — це механізм у JavaScript, при якому оголошення змінних і функцій "піднімаються" на початок своєї області видимості під час виконання коду, навіть якщо вони знаходяться після використання.
-
Основні моменти:
-
Оголошення змінних та функцій піднімаються: JavaScript піднімає лише оголошення, а не ініціалізацію змінних або значення функцій.
-
Функції: У разі функцій, які оголошуються через function (function declaration), піднімається і сама функція разом із її тілами.
-
Змінні: У разі змінних, оголошених через var, піднімається тільки оголошення, але не їх ініціалізація (значення). У результаті, змінна буде існувати, але її значення буде undefined до моменту присвоєння.
-
Приклад 1: Функції
console.log(greet()); // "Hello!" function greet() { return "Hello!"; }
-
У цьому прикладі виклик
greet()
працює, навіть якщо викликається до її оголошення. Це відбувається через підняття, оскільки функція повністю піднімається разом зі своїм тілом. -
Приклад 2: Змінні
console.log(a); // undefined var a = 5; console.log(a); // 5
-
У цьому прикладі змінна a спочатку матиме значення undefined, оскільки лише оголошення (але не ініціалізація) змінної піднімається. Після присвоєння значення a стає 5.
-
Підняття з let та const
-
Змінні, оголошені через let або const, не піднімаються так, як var. Вони знаходяться у "мертвої зони" (Temporal Dead Zone) між початком області видимості та місцем їх оголошення, що означає, що до того, як значення змінної буде присвоєно, їх не можна використовувати.
console.log(a); // ReferenceError: Cannot access 'a' before initialization let a = 5;
-
Тут виклик змінної до її ініціалізації викличе помилку, тому що змінна знаходиться в "мертвій зоні".
-
Висновок:
- Підняття дозволяє використовувати функції та змінні до їх фактичного оголошення в коді, але для змінних, оголошених через var, значення буде undefined до присвоєння, а для змінних, оголошених через let або const, це призведе до помилки, якщо спробувати доступитися до них до ініціалізації.
47. Що таке область видимості (Scope)?
-
Область видимості (Scope) в JavaScript — це контекст, у якому визначаються змінні, функції та інші ідентифікатори. Область видимості визначає, де саме в коді можна звертатися до цих змінних або функцій.
-
Типи областей видимості:
-
Глобальна область видимості:
- Це область, яка доступна в будь-якому місці вашого коду.
- Змінні та функції, оголошені поза будь-якими функціями або блоками, мають глобальну область видимості.
let globalVar = "I'm global"; function test() { console.log(globalVar); // Доступ до глобальної змінної } test(); console.log(globalVar); // Також доступно поза функцією
-
Область видимості функції (Function Scope):
- Кожна функція має свою область видимості, і змінні, оголошені всередині функції, доступні тільки в цій функції.
function test() { let localVar = "I'm local"; console.log(localVar); // Доступ до localVar всередині функції } test(); console.log(localVar); // Помилка: localVar не існує за межами функції
-
Область видимості блоку (Block Scope):
- Змінні, оголошені за допомогою
let
абоconst
, мають область видимості на рівні блоку (в межах{}
).
if (true) { let blockVar = "I'm block-scoped"; console.log(blockVar); // Доступно всередині блоку } console.log(blockVar); // Помилка: blockVar не доступно поза блоком
- Змінні, оголошені за допомогою
-
Лексичний Scope (Lexical Scope):
- Лексичний
scope
визначається на етапі написання коду, а не виконання. Це означає, що область видимості функцій визначається тим, де вони були оголошені, а не тим, де вони викликаються.
function outer() { let outerVar = "I'm outer"; function inner() { console.log(outerVar); // Доступ до outerVar через лексичний scope } inner(); } outer();
- Лексичний
-
Важливі моменти:
- Глобальні змінні доступні в усьому коді, але їх використання може призвести до проблем, якщо імена змінних збігаються.
- Функціональні змінні доступні тільки в межах функції.
- Змінні в межах блоку з
let
іconst
доступні лише в тому блоці, в якому вони оголошені.
-
Підсумок:
- Область видимості визначає, де змінні і функції можуть бути використані. Правильне розуміння області видимості допомагає уникати помилок, пов'язаних з доступом до змінних і функцій у некоректних місцях.
48. Навіщо використовується директива use strict?
-
Директива
"use strict"
в JavaScript вмикає строгий режим виконання, який змінює поведінку мови, роблячи її менш поблажливою до помилок. Вона допомагає писати більш безпечний і надійний код, запобігаючи потенційним проблемам. -
Основні цілі:
- Заборона використання небезпечних або застарілих функцій.
- Посилення перевірок синтаксису.
- Попередження прихованих помилок, роблячи їх явними.
- Що змінює строгий режим?
-
Заборона використання змінних без оголошення:
"use strict"; myVar = 10; // Помилка: myVar не оголошена
-
Обмеження з
this
у функціях:- У глобальному контексті this дорівнює undefined, а не глобальному об'єкту.
"use strict"; function test() { console.log(this); // undefined } test();
-
Заборона дублювання імен параметрів функцій:
"use strict"; function sum(a, a) { // Помилка: дублювання імен параметрів return a + a; }
-
Заборона видалення незмінних властивостей:
"use strict"; delete Object.prototype; // Помилка
-
Заборона застарілих синтаксичних конструкцій:
Наприклад, восьмеричні літерали (0123
) заборонені.
-
Більш безпечна робота з об'єктами:
- Запис у
read-only
властивість викликає помилку.
"use strict"; const obj = {}; Object.defineProperty(obj, "prop", { value: 42, writable: false }); obj.prop = 99; // Помилка
- Запис у
-
Як використовувати?
- У верхній частині файлу:
"use strict"; function test() { ... }
- У межах певної функції:
function test() { "use strict"; ... }
-
Чому це важливо?
- Полегшує відловлення помилок під час розробки.
- Допомагає уникати небажаних поведінок, які можуть призводити до багів.
- Забезпечує сумісність із новими версіями JavaScript.
-
Висновок:
"use strict"
забезпечує більш жорсткий, безпечний і передбачуваний підхід до написання JavaScript-коду.
49. Яке значення має this?
- Значення
this
залежить від контексту:
- Глобально або в функції (strict mode):
this
—undefined
. - Глобально або в функції (non-strict mode):
this
— глобальний об'єкт (window
в браузері,global
в Node.js). - У методі об'єкта:
this
посилається на об'єкт-власник методу. - У класі/конструкторі:
this
— новостворений об'єкт. - У стрілковій функції:
this
успадковується з контексту, де створена функція. - При явному прив'язуванні (call, apply, bind):
this
визначається вручну. - В обробнику подій:
this
залежить від способу прив’язки (елемент, обробник або явно встановлене).
50. Що таке прототип об'єкта?
-
Прототип об'єкта — це механізм JavaScript, який дозволяє об'єктам наслідувати властивості та методи від інших об'єктів. Кожен об'єкт має внутрішнє посилання на свій прототип, доступне через
[[Prototype]]
(або через__proto__
, хоча це застаріле). -
Основні моменти:
- Наслідування: Якщо об'єкт не має властивості чи методу, JavaScript шукає їх у його прототипі.
- Прототипний ланцюг: Пошук триває по ланцюгу прототипів до null (де ланцюг завершується).
- Встановлення прототипу: Через Object.create(), Object.setPrototypeOf() або шляхом використання class.
- Прототип об'єкта-конструктора: Новостворені об'єкти через new успадковують прототип, заданий властивістю prototype конструктора.
-
Простий приклад:
function Animal(name) { this.name = name; } Animal.prototype.speak = function () { return `${this.name} makes a noise.`; }; const dog = new Animal("Dog"); console.log(dog.speak()); // "Dog makes a noise."
51. Що таке IIFE?
-
IIFE (Immediately Invoked Function Expression) — це функція, яка викликається одразу після її оголошення. Вона використовується для створення ізольованого локального контексту, уникаючи забруднення глобального простору імен.
-
Синтаксис:
(function () { // Код виконується одразу })();
-
Або
(() => { // Код виконується одразу })();
-
Ключові аспекти:
- Замикання: IIFE створює новий лексичний контекст, дозволяючи ізолювати змінні.
- Глобальне забруднення: Уникнення додавання змінних в глобальний об'єкт.
- Одноразовий код: Зручне виконання коду, який не потрібно викликати повторно.
-
Приклад:
(function () { const message = "Hello, IIFE!"; console.log(message); // "Hello, IIFE!" })(); // message недоступна за межами IIFE
52. Навіщо використовується метод Function.prototype.apply?
-
Метод
Function.prototype.apply
використовується для виклику функції із вказаним значеннямthis
та передачею аргументів у вигляді масиву або об'єктоподібного елемента. -
Основні використання:
-
Зміна контексту
this
: Метод дозволяє вручну встановити, що буде посиланнямthis
у функції.const obj = { name: "Alice" }; function greet(greeting) { return `${greeting}, ${this.name}`; } console.log(greet.apply(obj, ["Hello"])); // "Hello, Alice"
-
Передача аргументів у вигляді масиву: Зручно викликати функції, що очікують список аргументів.
const numbers = [1, 2, 3, 4, 5]; console.log(Math.max.apply(null, numbers)); // 5
-
Використання для наслідування: Дає змогу викликати конструктор одного класу в контексті іншого.
function Animal(name) { this.name = name; } function Dog(name, breed) { Animal.apply(this, [name]); this.breed = breed; } const myDog = new Dog("Rex", "Labrador"); console.log(myDog); // { name: 'Rex', breed: 'Labrador' }
-
Відмінність від
call
:apply
приймає аргументи у вигляді масиву, тоді якcall
— як список.
53. Навіщо використовується метод Function.prototype.call?
-
Метод
Function.prototype.call
використовується для виклику функції із вказаним значеннямthis
і передачею аргументів як окремого списку. -
Основні використання:
-
Зміна контексту
this
: Дає можливість явно вказати, що буде значеннямthis
для функції.const obj = { name: "Alice" }; function greet(greeting) { return `${greeting}, ${this.name}`; } console.log(greet.call(obj, "Hello")); // "Hello, Alice"
-
Передача аргументів:
- Усі аргументи передаються окремо, а не масивом.
function sum(a, b, c) { return a + b + c; } console.log(sum.call(null, 1, 2, 3)); // 6
-
Наслідування функцій: Дозволяє викликати метод одного об’єкта для іншого.
const person = { fullName: function () { return `${this.firstName} ${this.lastName}`; }, }; const john = { firstName: "John", lastName: "Doe" }; console.log(person.fullName.call(john)); // "John Doe"
-
Імітація конструктора батьківського класу: Використовується для виклику конструктора іншого класу.
function Animal(name) { this.name = name; } function Dog(name, breed) { Animal.call(this, name); this.breed = breed; } const dog = new Dog("Rex", "Labrador"); console.log(dog); // { name: 'Rex', breed: 'Labrador' }
- Відмінність від
apply
:call
приймає аргументи через список.apply
приймає аргументи у вигляді масиву.
54. У чому різниця між методами call та apply?
- Різниця між методами
call
таapply
полягає у способі передачі аргументів:
call
:
-
Аргументи передаються як окремий список.
function greet(greeting, punctuation) { return `${greeting}, ${this.name}${punctuation}`; } const person = { name: "Alice" }; console.log(greet.call(person, "Hello", "!")); // "Hello, Alice!"
apply
:
-
Аргументи передаються у вигляді масиву або об'єктоподібного елемента.
function greet(greeting, punctuation) { return `${greeting}, ${this.name}${punctuation}`; } const person = { name: "Alice" }; console.log(greet.apply(person, ["Hello", "!"])); // "Hello, Alice!"
-
Схожість:
- Обидва змінюють контекст
this
. - Використовуються для передачі аргументів до функції.
- Обидва змінюють контекст
-
Коли що використовувати:
call
: Коли аргументи відомі та передаються як список.apply
: Коли аргументи динамічні або доступні як масив (наприклад, зMath.max
).
55. Навіщо використовується метод Function.prototype.bind?
-
Метод
Function.prototype.bind
використовується для створення нової функції з фіксованим значеннямthis
і, за потреби, попередньо заданими аргументами. -
Основні використання:
-
Фіксація контексту
this
:- Дозволяє гарантувати, що функція завжди викликатиметься з визначеним
this
, незалежно від місця її виклику.
const obj = { name: "Alice" }; function greet() { return `Hello, ${this.name}`; } const boundGreet = greet.bind(obj); console.log(boundGreet()); // "Hello, Alice"
- Дозволяє гарантувати, що функція завжди викликатиметься з визначеним
-
Попереднє встановлення аргументів:
- Можна частково передати аргументи, створюючи функцію із заздалегідь заповненими параметрами (каррінг).
function multiply(a, b) { return a * b; } const double = multiply.bind(null, 2); console.log(double(5)); // 10
-
Використання в колбек-функціях:
- Гарантує, що метод викликатиметься з правильним контекстом у функціях зворотного виклику.
const obj = { name: "Alice", greet() { console.log(`Hello, ${this.name}`); }, }; const greetFn = obj.greet.bind(obj); setTimeout(greetFn, 1000); // "Hello, Alice"
-
Неможливість зміни
this
:- Функція, створена через
bind
, не дозволяє змінитиthis
іншими методами, наприклад,call
чиapply
.
- Функція, створена через
-
Відмінність від
call
іapply
:bind
створює нову функцію з прив'язанимthis
, яку можна викликати пізніше.call
іapply
викликають функцію негайно.
56. Що таке функціональне програмування?
-
Функціональне програмування — це парадигма програмування, яка зосереджена на використанні функцій як основних будівельних блоків програм. Вона передбачає обробку даних через чисті функції, що не мають побічних ефектів, і використання високого рівня абстракції для маніпулювання даними.
-
Основні принципи функціонального програмування:
- Чисті функції: Функції, що для однакових вхідних значень завжди повертають однакові результати і не мають побічних ефектів (не змінюють стан програми чи глобальні змінні).
- Немутованість: Дані не змінюються, а замість цього створюються нові значення.
- Функції як першокласні об'єкти: Функції можна передавати як аргументи, повертати з інших функцій і зберігати в змінних.
- Вищий порядок функцій: Функції, які приймають інші функції як аргументи або повертають їх.
- Лінійна композиція: Композиція функцій для створення нових функцій, які виконують кілька операцій в одному виразі.
57. Які особливості JS дозволяють говорити про нього як про функціональну мову програмування?
- Особливості JavaScript, що підтримують функціональний стиль:
-
Функції першого класу: Функції можуть бути збережені в змінних, передаватися як аргументи іншим функціям і повертатися з функцій.
const add = (a, b) => a + b; const multiply = (a, b) => a * b; const apply = (fn, a, b) => fn(a, b); console.log(apply(add, 2, 3)); // 5
-
Вищі функції: JavaScript підтримує функції, які приймають інші функції як аргументи або повертають їх.
const map = (arr, fn) => arr.map(fn); console.log(map([1, 2, 3], (x) => x * 2)); // [2, 4, 6]
-
Функції-стрілки (Arrow functions): Вони забезпечують короткий синтаксис для створення функцій, що часто використовуються в функціональному стилі.
const square = (x) => x * x;
-
Методи масивів: Методи, такі як
map
,filter
,reduce
, дозволяють обробляти колекції даних без змінення вихідних масивів, що є основним принципом функціонального програмування.const nums = [1, 2, 3, 4]; const squares = nums.map((x) => x * x);
-
Замикання: JavaScript підтримує замикання, що дозволяє створювати функції, які мають доступ до змінних зовнішнього контексту, навіть після того, як цей контекст вже завершив своє виконання.
function outer(x) { return function inner(y) { return x + y; }; } const addFive = outer(5); console.log(addFive(3)); // 8
-
Іммутабельність через бібліотеки: Хоча сам JavaScript не забороняє зміну даних, завдяки бібліотекам типу
Immutable.js
можна реалізувати немутованість у коді.- JavaScript підтримує функціональний стиль завдяки своїм властивостям, але він також підтримує об'єктно-орієнтований і імперативний стилі програмування, що робить його мультипарадигмовою мовою.
58. Що таке функції вищого ладу (Higher Order Functions)?
- Функції вищого порядку (Higher Order Functions, HOF) — це функції, які виконують одну або кілька з наступних операцій:
- Приймають одну або кілька функцій як аргументи.
- Повертають функцію як результат.
-
Приклад:
- Функція, що приймає іншу функцію як аргумент:
function applyOperation(a, b, operation) { return operation(a, b); } const add = (x, y) => x + y; console.log(applyOperation(2, 3, add)); // 5
- Функція, що повертає іншу функцію:
function multiplyBy(x) { return function (y) { return x * y; }; } const multiplyBy2 = multiplyBy(2); console.log(multiplyBy2(5)); // 10
-
Приклади стандартних функцій вищого порядку:
map()
: Приймає функцію як аргумент і застосовує її до кожного елемента масиву, повертаючи новий масив.
const nums = [1, 2, 3]; const squared = nums.map(x => x \* x); console.log(squared); // [1, 4, 9]
filter()
: Приймає функцію як аргумент для фільтрації елементів масиву.
const nums = [1, 2, 3, 4, 5]; const even = nums.filter((x) => x % 2 === 0); console.log(even); // [2, 4]
reduce()
: Приймає функцію як аргумент для зменшення масиву до одного значення.
const nums = [1, 2, 3, 4]; const sum = nums.reduce((acc, x) => acc + x, 0); console.log(sum); // 10
-
Особливості:
- Функції як аргументи дозволяють передавати поведінку в інші функції.
- Функції як результати дозволяють створювати нові функції на основі вже існуючих, забезпечуючи високий рівень абстракції.
59. Чому функції JS називають об'єктами першого класу (First-class Objects)?
- Функції в JavaScript називають об'єктами першого класу (first-class objects), тому що вони володіють наступними властивостями, які характерні для об'єктів першого класу:
-
Можуть бути збережені в змінних:
- Функції можуть бути присвоєні змінним або передаватися як значення.
const greet = function () { console.log("Hello!"); }; greet(); // "Hello!"
-
Можуть бути передані як аргументи іншим функціям:
- Функції можуть бути передані в якості параметрів іншим функціям.
function callFunction(fn) { fn(); } callFunction(greet); // "Hello!"
-
Можуть бути повернуті як результат з інших функцій:
- Функції можуть бути повернуті іншими функціями, дозволяючи створювати нові функції на основі існуючих.
function createAdder(x) { return function (y) { return x + y; }; } const add5 = createAdder(5); console.log(add5(3)); // 8
-
Можуть бути динамічно створені в будь-який час:
- Функції в JavaScript можна створювати на льоту, як анонімні функції або через функції-стрілки.
- Ці властивості роблять функції в JavaScript такими ж важливими та гнучкими, як і інші типи даних, дозволяючи використовувати їх як об'єкти першого класу в програмі.
60. Що таке об'єкт arguments?
-
Об'єкт
arguments
— це вбудований об'єкт, доступний всередині функції, який містить усі аргументи, передані в цю функцію, незалежно від того, скільки параметрів було оголошено в сигнатурі функції. Він дозволяє працювати з переданими аргументами, навіть якщо їх кількість не збігається з кількістю параметрів у функції. -
Основні характеристики об'єкта
arguments
:
-
Масивоподібний об'єкт:
- Він має індекси для кожного переданого аргументу і властивість
length
, яка вказує на кількість переданих аргументів. Однак об'єктarguments
не є справжнім масивом, тому не має методів масиву, таких якmap
,forEach
тощо.
- Він має індекси для кожного переданого аргументу і властивість
-
Доступ до аргументів за індексом: Ви можете звертатися до переданих аргументів за індексом, як до елементів масиву.
function sum() { console.log(arguments[0]); // перший аргумент console.log(arguments[1]); // другий аргумент } sum(1, 2); // 1 2
-
Кількість аргументів: Ви можете використовувати властивість
length
для отримання кількості переданих аргументів.function logArgs() { console.log(arguments.length); } logArgs(1, 2, 3); // 3
-
Обмеження:
- Об'єкт
arguments
не підтримує методи масиву (якщо не використовувати додаткові методи для конвертації в масив). - Не є доступним у стрілкових функціях, оскільки стрілкові функції не мають власного об'єкта
arguments
.
- Об'єкт
-
Приклад:
function example() { console.log(arguments); // Масивоподібний об'єкт console.log(arguments.length); // Кількість аргументів console.log(arguments[0]); // Перший аргумент } example(1, "two", true); // Виведе: // [1, "two", true] // 3 // 1
-
Перетворення в масив:
- Оскільки
arguments
не є справжнім масивом, для використання масивних методів можна його перетворити в масив:
function example() { const args = Array.from(arguments); // або [...arguments] console.log(args.map((x) => x * 2)); } example(1, 2, 3); // [2, 4, 6]
- Оскільки
-
Використання: Об'єкт
arguments
корисний для роботи з функціями, коли кількість аргументів невідома, або коли ви хочете працювати з переданими аргументами незалежно від їх кількості.
61. Як створити об'єкт, який не має прототипу?
-
Щоб створити об'єкт без прототипу в JavaScript, використовується метод
Object.create(null)
. Це створює об'єкт, який не має властивостей і методів, успадкованих відObject.prototype
. -
Приклад:
const obj = Object.create(null); console.log(obj); // {} console.log(Object.getPrototypeOf(obj)); // null console.log(obj.hasOwnProperty); // undefined
-
Особливості такого об'єкта:
-
Відсутність прототипу: Об'єкт не має стандартних методів, таких як
toString
,hasOwnProperty
, які успадковуються відObject.prototype
. -
Корисний для створення чистих словників: Використовується, якщо ви хочете створити об'єкт як чистий хеш-таблицю, де всі ключі є власними властивостями, без конфліктів із методами або властивостями прототипу.
const dictionary = Object.create(null); dictionary.key = "value"; console.log(dictionary.key); // "value" console.log(dictionary.toString); // undefined
-
Обмеження: Ви не можете безпосередньо використовувати методи
Object.prototype
(наприклад,hasOwnProperty
), тому доведеться застосовувати їх через об'єктObject
.
-
Як викликати метод
hasOwnProperty
у такому об'єкті:const obj = Object.create(null); obj.key = "value"; // Використання Object.prototype.hasOwnProperty console.log(Object.prototype.hasOwnProperty.call(obj, "key")); // true
-
Цей підхід дозволяє уникати помилок, пов'язаних із успадкованими властивостями.
62. Що таке ECMAScript?
-
ECMAScript (ES) — це специфікація мови програмування, яка слугує стандартом для JavaScript, а також інших мов, таких як JScript і ActionScript. Вона визначає синтаксис, семантику та базову функціональність мови програмування.
-
Основні аспекти:
-
Стандартізація:
- ECMAScript розробляється та підтримується організацією ECMA International, а саме її технічним комітетом TC39.
-
Відносини з JavaScript:
- JavaScript є реалізацією специфікації ECMAScript, тобто браузери та інші середовища виконання використовують ECMAScript як основу для впровадження JavaScript.
-
Історія версій:
- ES3 (1999): Перший широко підтримуваний стандарт.
- ES5 (2009): Додав підтримку
strict mode
, JSON, нові методи масивів. - ES6 (ES2015): Значне оновлення з новими можливостями, такими як
let
,const
, стрілкові функції, класи, модулі. - Наступні версії (ES2016, ES2017 тощо) випускаються щороку, додаючи поступові покращення (наприклад,
async/await
, оператор??
, методиincludes
).
-
Особливості ECMAScript:
- Визначає синтаксис (наприклад, як оголошуються змінні, функції).
- Встановлює базові об'єкти (
Object
,Array
,Date
). - Регулює поведінку виконання коду (обробка помилок, область видимості тощо).
- Чому це важливо:
- ECMAScript гарантує сумісність та стандартизацію між різними реалізаціями JavaScript у браузерах, серверах та інших середовищах.
63. У чому різниця між ключовими словами var, let та const?
- Різниця між
var
,let
таconst
у JavaScript пов'язана з їхньою областю видимості, можливістю перевизначення та поведінкою при використанні.
-
var
-
Область видимості: Функціональна або глобальна.
var
ігнорує блочну область (наприклад, у циклах чи умовах).if (true) { var x = 10; } console.log(x); // 10
-
Підняття (Hoisting): Оголошення
var
піднімається на початок області, але значення залишаєтьсяundefined
до моменту присвоєння.console.log(a); // undefined var a = 5;
-
Перевизначення: Можна перевизначити або повторно оголосити ту саму змінну в тій же області.
var a = 5; var a = 10; // Допустимо
-
-
let
- Область видимості: Блочна (межі {}). Значення
let
існує тільки в межах блоку, де вона оголошена.
if (true) { let y = 20; } console.log(y); // Помилка: y is not defined
- Підняття (Hoisting): Оголошення піднімається, але перебуває у "темній зоні" (
Temporal Dead Zone
) до моменту ініціалізації.
console.log(b); // Помилка: Cannot access 'b' before initialization let b = 5;
- Перевизначення: Не можна повторно оголосити змінну з тим самим ім'ям у межах однієї області.
let c = 10; let c = 20; // Помилка: Identifier 'c' has already been declared
- Область видимості: Блочна (межі {}). Значення
-
const
-
Область видимості: Блочна, як і у let.
-
Підняття (Hoisting): Аналогічно let, перебуває у "темній зоні".
-
Перевизначення: Значення змінної const не можна змінити після ініціалізації.
const z = 30; z = 40; // Помилка: Assignment to constant variable
- Модифікація об’єктів: Об'єкти та масиви, оголошені через const, можуть бути змінені, але не може бути змінена сама змінна.
const obj = { a: 1 }; obj.a = 2; // Допустимо obj = {}; // Помилка
-
-
Коротко:
Властивість var
let
const
Область видимості Функціональна/глобальна Блочна Блочна Підняття (Hoisting) Так (значення undefined
)Так ("темна зона") Так ("темна зона") Перевизначення Дозволено Заборонено Заборонено Зміна значення Дозволено Дозволено Заборонено
64. Що таке класи (Classes)?
-
Класи в JavaScript — це синтаксичний цукор над прототипним успадкуванням, яка спрощує створення об'єктів і роботи з ними. Вони були введені в ECMAScript 2015 (ES6) і дозволяють більш зручну організацію коду, схожу на інші об'єктно-орієнтовані мови.
-
Основні характеристики:
-
Оголошення класу: Класи визначаються за допомогою ключового слова
class
.class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { return `Hi, I'm ${this.name} and I'm ${this.age} years old.`; } } const person = new Person("Alice", 30); console.log(person.greet()); // Hi, I'm Alice and I'm 30 years old.
-
Конструктор (
constructor
):- Метод, який викликається під час створення екземпляра класу.
- В ньому зазвичай ініціалізуються властивості об'єкта.
class Animal { constructor(type) { this.type = type; } } const cat = new Animal("Cat"); console.log(cat.type); // Cat
-
Методи класу:
- Методи, які є загальними для всіх екземплярів.
class MathOperations { add(a, b) { return a + b; } } const math = new MathOperations(); console.log(math.add(2, 3)); // 5
-
Статичні методи (
static
):- Прив'язані до самого класу, а не до його екземплярів.
class Calculator { static multiply(a, b) { return a * b; } } console.log(Calculator.multiply(4, 5)); // 20
-
Наслідування (
extends
):- Дозволяє створювати класи, що успадковують властивості та методи іншого класу.
class Animal { constructor(name) { this.name = name; } speak() { return `${this.name} makes a noise.`; } } class Dog extends Animal { speak() { return `${this.name} barks.`; } } const dog = new Dog("Rex"); console.log(dog.speak()); // Rex barks.
-
Гетери та сетери:
- Методи, які дозволяють отримувати або встановлювати значення властивостей.
class Rectangle { constructor(width, height) { this.width = width; this.height = height; } get area() { return this.width * this.height; } set resize(newWidth) { this.width = newWidth; } } const rect = new Rectangle(5, 10); console.log(rect.area); // 50 rect.resize = 8; console.log(rect.area); // 80
- Чому класи корисні?
- Зрозуміла структура: Полегшують читання та розуміння коду.
- Інкапсуляція: Забезпечують приховування деталей реалізації.
- Повторне використання: Завдяки наслідуванню.
- Сумісність з прототипним підходом: Під капотом класи все ще використовують прототипи.
65. Що таке шаблонні літерали (Template Literals)?
-
Шаблонні літерали (
Template Literals
) — це синтаксис для створення рядків у JavaScript, який дозволяє використовувати багатоособливостей, таких як інтерполяція змінних, багаторядкові рядки та додавання виразів. Вони були введені в ES6 (ECMAScript 2015). -
Синтаксис:
- Шаблонні літерали оголошуються за допомогою зворотних лапок (``), а не звичайних лапок ' або ".
-
Основні можливості:
-
Інтерполяція змінних і виразів: Використовується синтаксис ${...} для вставлення змінних або виразів у рядок.
const name = "Alice"; const age = 30; console.log(`Hi, my name is ${name} and I am ${age} years old.`); // Hi, my name is Alice and I am 30 years old.
-
Багаторядкові рядки: Шаблонні літерали дозволяють створювати багаторядкові рядки без використання символів переносу \n.
const message = `This is a multi-line string.`; console.log(message); // This is a // multi-line string.
-
Вбудовані вирази: В шаблон можна вставляти не лише змінні, але й будь-які JavaScript вирази.
const a = 5; const b = 10; console.log(`The sum of ${a} and ${b} is ${a + b}.`); // The sum of 5 and 10 is 15.
-
Виклик функцій у шаблоні:
const getGreeting = () => "Hello!"; console.log(`${getGreeting()}, world!`); // Hello!, world!
-
Використання з тегованими шаблонними літералами (Tagged Templates): Теговані шаблони дозволяють обробляти рядок за допомогою функції перед відображенням.
function tag(strings, ...values) { return strings[0] + values.map((v) => v.toUpperCase()).join(""); } const name = "Alice"; console.log(tag`Hello, ${name}!`); // Hello, ALICE!
-
Чому шаблонні літерали корисні:
-
Зручність і читабельність:
- Спрощують створення динамічних рядків.
- Легше писати багаторядкові рядки.
-
Менше помилок:
- Відсутність необхідності вручну конкатенувати рядки з +.
-
Розширюваність:
- Можливість використовувати теговані шаблони для складних обробок тексту (наприклад, переклад, перевірка безпеки даних тощо).
-
-
Приклад:
const user = { name: "John", age: 25, }; const greeting = `User ${user.name} is ${user.age} years old.`; console.log(greeting); // User John is 25 years old.
66. Що таке модулі (Modules)?
-
Модулі (Modules) в JavaScript — це спосіб організації коду, який дозволяє розбивати програму на менші, ізольовані частини (файли) з чітко визначеними залежностями. Модулі допомагають зробити код більш структурованим, повторно використовуваним і легшим у підтримці.
-
Основні концепції модулів:
-
Експорт (
export
):-
Використовується для визначення, які частини коду модуль робить доступними для інших файлів.
-
Існують два види експорту:
- Іменований експорт (export):
export const name = "Alice"; export function greet() { return "Hello!"; }
- Експорт за замовчуванням (export default):
export default function greet() { return "Hello, world!"; }
-
-
Імпорт (
import
):-
Використовується для підключення функцій, змінних або об'єктів з іншого модуля.
-
Іменований імпорт:
import { name, greet } from "./module.js"; console.log(name); // Alice console.log(greet()); // Hello!
-
Імпорт за замовчуванням:
import greet from "./module.js"; console.log(greet()); // Hello, world!
-
-
Строгий режим: Усі модулі працюють у строгому режимі (
strict mode
) за замовчуванням. -
Одинична область видимості:
- Кожен модуль має власну область видимості, що запобігає конфліктам змінних з іншими модулями.
- Переваги модулів:
-
Ізоляція:
- Уникнення глобального простору імен.
-
Повторне використання коду:
- Можливість експортувати та імпортувати компоненти між різними частинами програми.
-
Простота підтримки:
- Легше працювати з невеликими частинами коду.
-
Ясність залежностей:
- Модулі чітко вказують, які частини коду їм потрібні.
-
Приклад:
math.js
(модуль):export const add = (a, b) => a + b; export const subtract = (a, b) => a - b; export default (a, b) => a \* b; // Експорт за замовчуванням
app.js
(основний файл):import multiply, { add, subtract } from "./math.js"; console.log(add(2, 3)); // 5 console.log(subtract(7, 4)); // 3 console.log(multiply(3, 4)); // 12
-
Умови використання: - Модулі вимагають, щоб файли були з розширенням
.js
або.mjs
. - У браузерах потрібно використовувати атрибутtype="module"
у<script>
:<script type="module" src="app.js"></script>
- Для Node.js модулі доступні через import/export (ESM) або require (CommonJS).
-
Різновиди модулів:
- ESM (ECMAScript Modules):
- Вбудований стандарт із використанням import/export.
- Сучасний підхід.
-
CommonJS:
- Використовується в Node.js (require/module.exports).
- Старіший підхід, менш зручний для браузерів.
67. Навіщо потрібен оператор опціональної послідовності?
-
Оператор опціональної послідовності (Optional Chaining,
?.
) використовується для безпечного доступу до властивостей об'єкта або виклику методів, навіть якщо деякі з цих властивостей або методів можуть бутиnull
абоundefined
. Він запобігає помилкам типуCannot read property of undefined
. -
Як працює:
- Перевіряє наявність властивості: Якщо властивість існує, повертає її значення. Інакше повертає
undefined
. - Припиняє виконання, якщо значення
null
абоundefined
: Не викликає помилок і просто повертаєundefined
.
- Приклади використання:
-
Доступ до вкладених властивостей:
- Без оператора:
const user = { profile: { name: "Alice" } }; console.log(user.profile.name); // Alice console.log(user.address.city); // Помилка
- З оператором:
const user = { profile: { name: "Alice" } }; console.log(user.profile?.name); // Alice console.log(user.address?.city); // undefined
-
Виклик методів:
const user = { greet() { return "Hello!"; }, }; console.log(user.greet?.()); // Hello! console.log(user.sayGoodbye?.()); // undefined
-
Доступ до елементів масиву:
const data = null; console.log(data?.[0]); // undefined
-
Комбінування з оператором Nullish Coalescing (
??
): Для встановлення значення за замовчуванням:const user = null; console.log(user?.profile?.name ?? "Default Name"); // Default Name
- Навіщо це потрібно:
-
Запобігання помилок: Уникає аварійного завершення програми через доступ до невизначених властивостей.
-
Зручність: Код стає коротшим і зрозумілішим.
-
Безпека: Не потрібно вручну перевіряти кожен рівень вкладеності:
if (user && user.profile && user.profile.name) { console.log(user.profile.name); } // Заміна: console.log(user?.profile?.name);
-
Коли використовувати:
- При роботі з глибоко вкладеними об'єктами або даними, які можуть бути частково відсутні (наприклад, відповіді API).
68. Що таке генератори?
-
Генератори — це функції в JavaScript, які можуть призупиняти виконання та відновлювати його пізніше, що дозволяє створювати послідовності значень або керувати асинхронним кодом. Генератори визначаються за допомогою ключового слова
function*
і використовують операторyield
для повернення проміжних результатів. -
Основні властивості генераторів:
-
Призупинення виконання:
- Використання оператора
yield
дозволяє зупинити виконання функції та повернути значення.
- Використання оператора
-
Відновлення виконання:
- Метод
next()
відновлює виконання з того місця, де було зупинено.
- Метод
-
Ітератори:
- Генератори є ітераторами, тому їх можна використовувати в циклах
for...of
та інших контекстах ітерації.
- Генератори є ітераторами, тому їх можна використовувати в циклах
-
Синтаксис:
-
Оголошення генератора:
function* generatorFunction() { yield "First value"; yield "Second value"; return "Done"; }
-
Використання:
const gen = generatorFunction(); console.log(gen.next()); // { value: "First value", done: false } console.log(gen.next()); // { value: "Second value", done: false } console.log(gen.next()); // { value: "Done", done: true } console.log(gen.next()); // { value: undefined, done: true }
-
-
Приклади використання:
- Створення послідовностей:
function* count() { let i = 0; while (true) { yield i++; } } const counter = count(); console.log(counter.next().value); // 0 console.log(counter.next().value); // 1 console.log(counter.next().value); // 2
-
Перебір значень за допомогою
for...of
:function* colors() { yield "red"; yield "green"; yield "blue"; } for (const color of colors()) { console.log(color); } // red // green // blue
-
Керування асинхронним кодом: Генератори можуть бути використані для асинхронного виконання з функціями, що повертатимуть проміси:
function* asyncGenerator() { console.log(yield Promise.resolve("First promise resolved")); console.log(yield Promise.resolve("Second promise resolved")); } const gen = asyncGenerator(); gen.next().value.then((result) => gen.next(result).value.then(console.log));
-
Симуляція нескінченних структур:
function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { yield curr; [prev, curr] = [curr, prev + curr]; } } const fib = fibonacci(); console.log(fib.next().value); // 1 console.log(fib.next().value); // 1 console.log(fib.next().value); // 2 console.log(fib.next().value); // 3
- Переваги:
- Контроль виконання: Генератори дають змогу вручну керувати виконанням функції.
- Легкість створення послідовностей: Простий спосіб створювати ітеративні послідовності.
- Асинхронне програмування: Спрощують управління асинхронними потоками даних (особливо до введення async/await).
- Обмеження:
- Генератори не паралельні; виконання призупиняється тільки в межах поточного виклику.
- Асинхронність у генераторах менш інтуїтивна порівняно з async/await.
- Висновок: Генератори зручні для роботи з ітераторами, асинхронним кодом та складними послідовностями.
69. Що таке регулярні вирази (RegEx)?
-
Регулярні вирази (Regular Expressions, RegEx) — це шаблони, які використовуються для пошуку, перевірки, або маніпулювання текстом. Вони дозволяють ефективно працювати з текстовими рядками за допомогою спеціального синтаксису.
-
Основні можливості:
- Пошук: Знаходження підрядків у тексті.
- Перевірка: Визначення, чи відповідає текст певному шаблону.
- Заміна: Модифікація тексту на основі відповідностей.
-
Синтаксис:
-
Оголошення регулярного виразу:
Літеральна нотація:
const regex = /pattern/flags;
Конструктор:
const regex = new RegExp("pattern", "flags");
-
Прапори (Flags):
g
— Глобальний пошук (не зупиняється на першій відповідності).i
— Ігнорування регістру.m
— Багаторядковий режим.s
— Дозволяє . збігатися з символом нового рядка.u
— Включає підтримку Юнікоду.y
— Суворий пошук з прив’язкою до позиції.
-
-
Приклади використання:
- Пошук тексту:
const text = "Hello World!"; const regex = /world/i; console.log(regex.test(text)); // true
- Заміна тексту:
const text = "foo bar foo"; const regex = /foo/g; console.log(text.replace(regex, "baz")); // "baz bar baz"
- Витяг відповідностей:
const text = "[email protected]"; const regex = /\w+@\w+\.\w+/; console.log(text.match(regex)); // ["[email protected]"]
-
Основні елементи шаблонів:
-
Літери та цифри: Збігаються з буквами та цифрами буквально.
-
Спеціальні символи:
.
— Будь-який символ (окрім нового рядка).\d
— Цифра (0-9).\w
— Будь-яка літера, цифра або _.\s
— Пробіл.\b
— Межа слова.^
— Початок рядка.$
— Кінець рядка.
-
Модифікатори:
+
— Один або більше.*
— Нуль або більше.?
— Нуль або один.{n}
— Рівно n разів.{n,}
— Щонайменше n разів.{n,m}
— Від n до m разів.
-
Групи та альтернація:
(abc)
— Групування.|
— Або (альтернація).
-
Екранування: Щоб використовувати спеціальний символ буквально, перед ним додається
\
:const regex = /\./; console.log("a.b".match(regex)); // ["."]
-
Приклад складного шаблону:
- Пошук номерів телефонів у форматі
+380-XX-XXX-XXXX
:
const regex = /\+380-\d{2}-\d{3}-\d{4}/; console.log("+380-67-123-4567".match(regex)); // ["+380-67-123-4567"]
- Пошук номерів телефонів у форматі
-
Переваги:
- Швидка перевірка текстових шаблонів.
- Універсальність: працюють у багатьох мовах програмування.
- Потужність: дозволяють описувати складні текстові патерни.
- Недоліки:
- Складність для читання та написання складних шаблонів.
- Потенційно повільне виконання на великих текстах із неефективними виразами.
- Висновок: Регулярні вирази — незамінний інструмент для роботи з текстами, якщо розуміти їхній синтаксис і використовувати обережно.
70. Що таке temporal dead zone?
-
Temporal Dead Zone (TDZ) — це проміжок часу між початком області видимості змінної, оголошеної через let або const, і моментом, коли ця змінна фактично ініціалізується. У цей період спроба доступу до змінної призведе до помилки
ReferenceError
. -
Як це працює:
- Змінні, оголошені за допомогою
let
іconst
, піднімаються (hoisting
), але не ініціалізуються. - Поки код не досягне місця, де змінна оголошена, вона перебуває в TDZ.
-
Приклад:
console.log(a); // ReferenceError: Cannot access 'a' before initialization let a = 5;
- Змінна a піднята (
hoisted
) на початок блоку, але не ініціалізована. - Вона перебуває у
TDZ
до моменту, коли код досягає її оголошення (let a = 5
).
- Змінна a піднята (
-
Особливості TDZ:
-
Область видимості:
TDZ
існує в межах блоку, функції чи скрипта, де змінна оголошена.{ console.log(x); // ReferenceError let x = 10; }
-
Функції та TDZ: Якщо змінна використовується в функції до її оголошення, це також викличе
ReferenceError
.function test() { console.log(y); // ReferenceError let y = 20; }
-
Відмінність від var: Змінні, оголошені через
var
, не маютьTDZ
. Вони ініціалізуються значеннямundefined
.console.log(b); // undefined var b = 15;
-
Навіщо це потрібно:
- Попередження помилок:
TDZ
захищає від доступу до змінної до її явного оголошення, зменшуючи кількість логічних помилок. - Забезпечення блочних областей видимості: Гарантує коректну роботу з блоками, особливо в умовах, де змінні часто переписуються.
- Попередження помилок:
-
Висновок:
Temporal Dead Zone
— це механізм, який покращує передбачуваність і безпеку коду, але вимагає уважного дотримання порядку оголошення змінних.
71. Яка різниця між function declaration та function expression?
Властивість | Function Declaration | Function Expression |
---|---|---|
Синтаксис | function name() { ... } |
const name = function() { ... }; або const name = () => { ... }; |
Ім’я функції | Обов’язкове | Може бути анонімною |
Підняття (Hoisting) | Піднімається повністю, доступна до виклику | Піднімається лише оголошення змінної, але не ініціалізація функції |
Використання до оголошення | Дозволено | Заборонено (отримаєте ReferenceError ) |
Зручність в рекурсії | Просте використання через ім’я функції | Для рекурсії потрібно використовувати ім’я змінної або arguments.callee |
Контекст | Підходить для декларативного оголошення | Часто використовується в якості значення змінної або параметра |
- Function Declaration:
// Оголошення
function greet() {
console.log("Hello!");
}
// Виклик до визначення — працює
greet(); // Hello!
- Function Expression:
// Оголошення
const greet = function () {
console.log("Hello!");
};
// Виклик до визначення — ReferenceError
greet(); // Hello!
-
Підняття:
Function Declaration
доступна до моменту оголошення завдяки hoisting.Function Expression
не піднімається з ініціалізацією; доступна тільки після оголошення.
-
Гнучкість:
Function Expression
може бути анонімною, використовуватись в колбеках і як значення змінної.Function Declaration
завжди має ім’я, зручне для читаємого та структурованого коду.
- Висновок: Використовуйте
Function Declaration
для глобальних функцій іFunction Expression
для динамічного створення або передачі функцій.
72. Типи таймерів у JavaScript?
- У JavaScript є два основні типи таймерів:
setTimeout
- Використовується для виконання коду один раз після заданої затримки (у мілісекундах).
- Повертає ідентифікатор таймера, який можна використовувати для скасування.
const timerId = setTimeout(() => {
console.log("Виконується через 2 секунди");
}, 2000);
// Скасування таймера
clearTimeout(timerId);
setInterval
- Використовується для виконання коду з фіксованим інтервалом часу (у мілісекундах).
- Повертає ідентифікатор таймера, який можна використовувати для скасування.
const intervalId = setInterval(() => {
console.log("Виконується кожні 3 секунди");
}, 3000);
// Скасування інтервалу
clearInterval(intervalId);
- Таймери не гарантують точність виконання через обмеження в Event Loop.
- Затримка не є мінімальним часом виконання, а лише інструкцією для Event Loop.
73. Які методи рядків у JavaScript ти знаєш?
- JavaScript надає різноманітні методи для роботи з рядками. Ось найпоширеніші:
length
- Повертає довжину рядка.
const str = "Hello, world!";
console.log(str.length); // 13
toUpperCase()
/toLowerCase()
- Перетворює рядок у верхній або нижній регістр.
console.log("hello".toUpperCase()); // "HELLO"
console.log("WORLD".toLowerCase()); // "world"
trim()
- Видаляє пробіли з початку та кінця рядка.
const str = " Hello! ";
console.log(str.trim()); // "Hello!"
includes()
- Перевіряє, чи міститься підрядок у рядку. Повертає true або false.
console.log("Hello, world!".includes("world")); // true
console.log("Hello, world!".includes("foo")); // false
indexOf()
/lastIndexOf()
- Повертає індекс першого або останнього входження підрядка. Повертає -1, якщо підрядок не знайдено.
console.log("Hello, world!".indexOf("o")); // 4
console.log("Hello, world!".lastIndexOf("o")); // 8
startsWith()
/endsWith()
- Перевіряє, чи починається або закінчується рядок на заданий підрядок.
console.log("Hello, world!".startsWith("Hello")); // true
console.log("Hello, world!".endsWith("world!")); // true
slice()
- Повертає частину рядка між заданими індексами.
console.log("Hello, world!".slice(0, 5)); // "Hello"
console.log("Hello, world!".slice(-6)); // "world!"
substring()
- Подібний до slice(), але не підтримує негативні індекси.
console.log("Hello, world!".substring(0, 5)); // "Hello"
console.log("Hello, world!".substring(7)); // "world!"
replace()
/replaceAll()
- Замінює частини рядка.
console.log("Hello, world!".replace("world", "JavaScript")); // "Hello, JavaScript!"
console.log("Hello, world! world!".replaceAll("world", "JS")); // "Hello, JS! JS!"
split()
- Розділяє рядок на масив підрядків за вказаним роздільником.
console.log("a,b,c".split(",")); // ["a", "b", "c"]
repeat()
- Повторює рядок задану кількість разів.
console.log("Ha!".repeat(3)); // "Ha!Ha!Ha!"
padStart()
/padEnd()
- Додає символи на початок або кінець рядка до заданої довжини.
console.log("5".padStart(3, "0")); // "005"
console.log("5".padEnd(3, "0")); // "500"
charAt()
/charCodeAt()
- Повертає символ або код символу за заданим індексом.
console.log("Hello".charAt(1)); // "e"
console.log("Hello".charCodeAt(1)); // 101
concat()
- Об'єднує рядки.
console.log("Hello".concat(", ", "world!")); // "Hello, world!"
match()
/matchAll()
- Шукає збіги за регулярним виразом.
console.log("abc123".match(/\d+/)); // ["123"]
console.log([..."abc123abc".matchAll(/abc/g)]); // [Array(1), Array(1)]
toString()
- Повертає рядкове представлення об'єкта.
const num = 123;
console.log(num.toString()); // "123"
- Ці методи дають широкий вибір для роботи з рядками в JavaScript.
74. Які методи масивів у JavaScript ти знаеш?
- JavaScript надає багатий набір методів для роботи з масивами. Нижче описані основні з них:
length
- Повертає кількість елементів у масиві.
const arr = [1, 2, 3];
console.log(arr.length); // 3
push()
/pop()
- Додає або видаляє елементи з кінця масиву.
const arr = [1, 2];
arr.push(3); // [1, 2, 3]
arr.pop(); // [1, 2]
unshift()
/shift()
- Додає або видаляє елементи з початку масиву.
const arr = [2, 3];
arr.unshift(1); // [1, 2, 3]
arr.shift(); // [2, 3]
forEach()
- Виконує задану функцію для кожного елемента масиву.
[1, 2, 3].forEach((num) => console.log(num));
// Виведе: 1, 2, 3
map()
- Створює новий масив, виконуючи функцію для кожного елемента.
const squared = [1, 2, 3].map((num) => num ** 2);
console.log(squared); // [1, 4, 9]
filter()
- Створює новий масив із елементів, що відповідають умові.
const even = [1, 2, 3, 4].filter((num) => num % 2 === 0);
console.log(even); // [2, 4]
reduce()
/reduceRight()
- Зводить масив до одного значення.
const sum = [1, 2, 3, 4].reduce((acc, num) => acc + num, 0);
console.log(sum); // 10
find()
/findIndex()
- Повертає перший елемент (або індекс), що відповідає умові.
const arr = [1, 2, 3, 4];
console.log(arr.find((num) => num > 2)); // 3
console.log(arr.findIndex((num) => num > 2)); // 2
some()
/every()
- Перевіряють, чи відповідає хоча б один або всі елементи умові.
console.log([1, 2, 3].some((num) => num > 2)); // true
console.log([1, 2, 3].every((num) => num > 0)); // true
sort()
- Сортує елементи масиву.
const arr = [3, 1, 4, 2];
arr.sort((a, b) => a - b); // [1, 2, 3, 4]
reverse()
- Змінює порядок елементів у масиві на протилежний.
const arr = [1, 2, 3];
arr.reverse(); // [3, 2, 1]
concat()
- Об'єднує масиви.
const arr1 = [1, 2];
const arr2 = [3, 4];
console.log(arr1.concat(arr2)); // [1, 2, 3, 4]
slice()
- Повертає частину масиву.
const arr = [1, 2, 3, 4];
console.log(arr.slice(1, 3)); // [2, 3]
splice()
- Додає, видаляє або замінює елементи в масиві.
const arr = [1, 2, 3, 4];
arr.splice(1, 2, "a", "b"); // [1, "a", "b", 4]
join()
- Об'єднує елементи масиву в рядок.
const arr = [1, 2, 3];
console.log(arr.join("-")); // "1-2-3"
flat()
/flatMap()
- Розгладжує вкладені масиви.
console.log([1, [2, [3]]].flat(2)); // [1, 2, 3]
console.log([1, 2, 3].flatMap((num) => [num, num * 2])); // [1, 2, 2, 4, 3, 6]
fill()
- Заповнює масив одним значенням.
const arr = [1, 2, 3];
arr.fill(0, 1); // [1, 0, 0]
Array.isArray()
- Перевіряє, чи є об'єкт масивом.
console.log(Array.isArray([1, 2, 3])); // true
console.log(Array.isArray("hello")); // false
- Ці методи забезпечують гнучкість для роботи з масивами у JavaScript.
75. Що таке чиста функція?
- Чиста функція (Pure Function) — це функція, яка має такі характеристики:
-
Детермінованість:
- Повертає однаковий результат для одного і того ж набору вхідних даних.
- Наприклад,
f(x) = x + 2
завжди поверне4
, якщоx = 2
.
-
Відсутність побічних ефектів:
- Функція не змінює зовнішній стан (наприклад, глобальні змінні, DOM, файли тощо).
- Всі операції виконуються лише в межах функції.
- Приклад чистої функції:
function add(a, b) {
return a + b;
}
console.log(add(2, 3)); // 5
-
Ця функція:
- Не змінює жодних зовнішніх змінних.
- Повертає однаковий результат для однакових аргументів.
-
Приклад нечистої функції:
let counter = 0;
function increment() {
counter++;
return counter;
}
console.log(increment()); // 1
console.log(increment()); // 2
-
Ця функція:
- Змінює зовнішню змінну counter.
- Має побічний ефект, тому не є чистою.
-
Переваги чистих функцій:
-
Передбачуваність:
- Легше тестувати та налагоджувати.
-
Референційна прозорість:
- Ви можете замінити виклик функції її результатом без зміни логіки.
-
Безпечність у паралельних обчисленнях:
- Відсутність побічних ефектів робить функції безпечними для багатопоточності.
- Чисті функції є важливим аспектом функціонального програмування, де функції використовуються як будівельні блоки для створення складних програм. Наприклад:
const double = (x) => x * 2;
const square = (x) => x * x;
const result = [1, 2, 3, 4].map(double).map(square);
console.log(result); // [4, 16, 36, 64]
- Тут double і square є чистими функціями.
76. Як визначити наявність властивості в об'єкті?
- Для перевірки, чи існує певна властивість в об'єкті в JavaScript, можна використовувати кілька підходів:
- Оператор
in
- Перевіряє наявність властивості (включаючи успадковані) в об'єкті.
const obj = { name: "Alice", age: 25 };
console.log("name" in obj); // true
console.log("address" in obj); // false
- Метод
hasOwnProperty
- Перевіряє лише власні властивості об'єкта (не успадковані).
const obj = { name: "Alice", age: 25 };
console.log(obj.hasOwnProperty("name")); // true
console.log(obj.hasOwnProperty("toString")); // false (успадкована)
- Перевірка на
undefined
- Працює, якщо значення властивості не є undefined.
const obj = { name: "Alice", age: 25 };
console.log(obj.name !== undefined); // true
console.log(obj.address !== undefined); // false
- Оператор доступу з умовною перевіркою (
?.
)
- Використовується для перевірки вкладених властивостей.
const obj = { user: { name: "Alice" } };
console.log(obj?.user?.name); // "Alice"
console.log(obj?.user?.address); // undefined
- Використовуйте
in
для перевірки всіх властивостей (включаючи успадковані). - Використовуйте
hasOwnProperty
, якщо потрібно перевірити лише власні властивості об'єкта.
77. Різниця між host-об'єктами та нативними об'єктами?
- JavaScript має два типи об'єктів: Host-об'єкти та Нативні об'єкти. Розглянемо їхні відмінності:
- Host-об'єкти
-
Це об'єкти, які надаються середовищем виконання (браузер, Node.js тощо).
-
Їхній набір залежить від середовища, в якому працює JavaScript.
-
Приклади в браузері:
window
document
console
XMLHttpRequest
fetch
-
Приклад:
console.log(window.innerWidth); // Ширина вікна браузера
console.log(document.title); // Назва сторінки
- Особливості:
- Не стандартизовані для всіх середовищ.
- Можуть містити специфічні методи та властивості для конкретного середовища.
- Нативні об'єкти
-
Це вбудовані об'єкти, які є частиною специфікації ECMAScript.
-
Вони доступні в будь-якому середовищі виконання JavaScript.
-
Приклади:
Object
Array
Function
Date
RegExp
-
Приклад:
const arr = [1, 2, 3];
console.log(arr.length); // 3
console.log(new Date().getFullYear()); // Поточний рік
-
Особливості:
- Завжди однакові незалежно від середовища.
- Визначені стандартом ECMAScript.
Критерій | Host-об'єкти | Нативні об'єкти |
---|---|---|
Джерело | Надаються середовищем виконання | Вбудовані у специфікацію ECMAScript |
Залежність від середовища | Залежать від середовища (браузер, Node.js) | Незалежні від середовища |
Приклади | window , document , console |
Object , Array , Date |
Стандартизація | Може бути специфічною для середовища | Стандартизовані в ECMAScript |
-
Рекомендації
- Використовуйте Нативні об'єкти для універсального та стандартного коду.
- Використовуйте Host-об'єкти лише для роботи з конкретним середовищем, наприклад, браузером або сервером Node.js.
78. Що таке об'єктна обгортка (Wrapper Objects)?
-
Об'єктна обгортка — це тимчасовий об'єкт, який створюється для примітивних типів (
string
,number
,boolean
) у JavaScript, щоб дозволити доступ до методів і властивостей, характерних для об'єктів. -
Примітиви в JavaScript самі по собі не є об'єктами, але під час доступу до методів або властивостей, JavaScript автоматично створює об'єктну обгортку.
- Коли викликається метод або властивість примітива:
- JavaScript створює тимчасовий об'єкт обгортки.
- Здійснюється доступ до методу/властивості через цей об'єкт.
- Після цього об'єкт-обгортка видаляється.
- Рядок (
String
)
const str = "hello";
console.log(str.toUpperCase()); // "HELLO"
// JavaScript створює тимчасовий об'єкт String:
// const temp = new String("hello");
// temp.toUpperCase(); -> "HELLO"
- Число(
Number
)
const num = 42;
console.log(num.toFixed(2)); // "42.00"
// JavaScript створює тимчасовий об'єкт Number:
// const temp = new Number(42);
// temp.toFixed(2); -> "42.00"
- Булеве значення (
Boolean
)
const bool = true;
console.log(bool.toString()); // "true"
// JavaScript створює тимчасовий об'єкт Boolean:
// const temp = new Boolean(true);
// temp.toString(); -> "true"
-
Тимчасовість
- Об'єктна обгортка створюється тільки на час доступу до методів/властивостей і видаляється одразу після використання.
-
Незмінність примітивів
- Оскільки примітиви є незмінними, зміни об'єктної обгортки не впливають на сам примітив.
const str = "hello";
str.tempProp = "value";
console.log(str.tempProp); // undefined
-
Після доступу до
str.tempProp
об'єкт-обгортка видаляється, тому змінена властивість не зберігається. -
Різниця між об'єктами та примітивами
- Примітиви: зберігають свої значення напряму.
- Об'єкти: є посиланням на область у пам'яті.
- Хоча об'єктні обгортки створюються автоматично, їх можна створити вручну за допомогою відповідних конструкторів.
const strObj = new String("hello");
console.log(typeof strObj); // "object"
- Проте такий підхід не рекомендується через непотрібність у звичайному використанні.
79. Навіщо використовується оператор залишку (%)?
- Оператор залишку (
%
) використовується для визначення залишку від ділення одного числа на інше. Він є корисним у багатьох сценаріях програмування.
- Оператор залишку обчислює залишок від ділення за формулою:
a % b = a - (Math.floor(a / b) * b)
- a — ділене.
- b — дільник.
- Результат — залишок від ділення.
- Обчислення залишку
console.log(10 % 3); // 1 (10 = 3 * 3 + 1)
console.log(25 % 4); // 1 (25 = 4 * 6 + 1)
- Робота з від'ємними числами
- У JavaScript залишок може бути від'ємним, якщо ділене негативне.
console.log(-10 % 3); // -1
console.log(10 % -3); // 1
-
Визначення парності числа
- Якщо залишок від ділення на 2 дорівнює 0, число парне.
- Якщо залишок не дорівнює 0, число непарне.
const isEven = (num) => num % 2 === 0;
console.log(isEven(4)); // true
console.log(isEven(7)); // false
- Циклічність (наприклад, індекси в масивах)
- Оператор залишку корисний для циклічного доступу до елементів.
const arr = ["a", "b", "c"];
const index = 5 % arr.length; // 5 % 3 = 2
console.log(arr[index]); // "c"
- Розподіл елементів
- Наприклад, для розподілу елементів по групах.
const groupByTwo = (arr) => {
const group1 = [];
const group2 = [];
arr.forEach((num) => {
if (num % 2 === 0) group1.push(num);
else group2.push(num);
});
return { group1, group2 };
};
console.log(groupByTwo([1, 2, 3, 4])); // { group1: [2, 4], group2: [1, 3] }
- Обмеження значення
- Наприклад, для обмеження значень у певному діапазоні.
const maxLimit = 5;
console.log(7 % maxLimit); // 2
- Оператор
%
є універсальним інструментом для роботи з залишками, перевірками на парність, циклічністю та розподілом. Його використання суттєво спрощує вирішення багатьох завдань у програмуванні.
80. Як працює boxing/unboxing у JavaScript?
- Boxing та Unboxing у JavaScript — це процес автоматичного перетворення між примітивними типами даних (наприклад,
number
,string
,boolean
) і їх об'єктними обгортками (Number
,String
,Boolean
).
- Boxing — це перетворення примітивного типу на об'єкт. Це відбувається автоматично, коли до примітивного значення застосовуються методи або властивості, які доступні тільки в об'єктах.
- JavaScript створює тимчасовий об'єкт обгортки для примітивного значення.
- Застосовує метод чи властивість.
- Видаляє тимчасовий об'єкт після використання.
const str = "hello";
console.log(str.toUpperCase()); // "HELLO"
- Boxing: створюється об'єкт
String("hello")
. - Викликається метод
toUpperCase()
. - Об'єкт видаляється, залишаючи результат
"HELLO"
.
-
Unboxing — це зворотний процес, коли значення з об'єктної обгортки отримується у вигляді примітивного типу.
-
Як це працює?
-
JavaScript викликає методи
valueOf()
абоtoString()
для об'єкта, щоб отримати його примітивне значення.
const num = new Number(42);
console.log(num + 8); // 50
- Unboxing: викликається num.valueOf(), щоб отримати 42.
- Виконується додавання: 42 + 8 = 50.
-
Об'єкти-обгортки
- JavaScript має вбудовані об'єкти-обгортки для кожного примітивного типу:
Примітивний тип | Об'єктна обгортка |
---|---|
string |
String |
number |
Number |
boolean |
Boolean |
symbol |
Symbol |
bigint |
BigInt |
- Приклад роботи з об'єктами-обгортками:
const strObj = new String("hello"); // Об'єкт
console.log(typeof strObj); // "object"
const strPrim = strObj.valueOf(); // Примітив
console.log(typeof strPrim); // "string"
-
Boxing — автоматичний процес:
- Коли ви використовуєте методи або властивості примітивного типу.
-
Unboxing — автоматичний процес:
- Відбувається, коли об'єкт використовується в контексті, який очікує примітив.
-
Різниця між примітивами та об'єктами:
- Примітиви порівнюються за значенням, а об'єкти за посиланням.
Приклад порівняння:
const str1 = "hello";
const str2 = new String("hello");
console.log(str1 == str2); // true (Unboxing str2 до примітиву)
console.log(str1 === str2); // false (Різні типи: примітив і об'єкт)
-
Висновок:
- Boxing і Unboxing автоматизують взаємодію між примітивними типами та об'єктами, що робить JavaScript більш гнучким для використання методів та властивостей примітивів. Це важливий механізм, який допомагає зберігати баланс між простотою та потужністю мови.
81. Що таке мемоізація?
- Мемоізація — це техніка оптимізації, яка зберігає результати виконання функцій для уникнення повторних обчислень при однакових вхідних даних.
- Функція перевіряє, чи результат для поточних аргументів вже збережений.
- Якщо збережений результат знайдено, повертається він.
- Якщо результату немає, функція обчислює його, зберігає у кеш і повертає.
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log("З кешу:", key);
return cache.get(key);
}
const result = fn(...args);
cache.set(key, result);
return result;
};
}
// Оригінальна функція
function slowFunction(num) {
console.log("Обчислення для:", num);
return num * num;
}
// Мемоізована версія
const memoizedFunction = memoize(slowFunction);
console.log(memoizedFunction(5)); // Обчислення для: 5, 25
console.log(memoizedFunction(5)); // З кешу: [5], 25
console.log(memoizedFunction(10)); // Обчислення для: 10, 100
console.log(memoizedFunction(10)); // З кешу: [10], 100
-
Переваги мемоізації:
- Підвищення продуктивності за рахунок уникнення повторних обчислень.
- Ефективне використання ресурсів.
-
Недоліки мемоізації:
- Збільшення споживання пам’яті через збереження кешу.
- Можливість застарілих даних у кеші.
-
Де використовується мемоізація?
- Веб-додатки (оптимізація рендерингу компонентів).
- Обчислення складних математичних операцій.
- Зберігання результатів запитів до API.
82. Різниця між глибокою (deep) та поверхневою (shallow) копіями об'єкта?
Критерій | Поверхнева копія (Shallow Copy) | Глибока копія (Deep Copy) |
---|---|---|
Що копіюється | Лише верхній рівень властивостей. | Усі рівні об'єкта, включаючи вкладені структури. |
Залежність | Вкладені об'єкти копіюються за посиланням (shared reference). | Вкладені об'єкти копіюються рекурсивно, створюючи нові екземпляри. |
Ризик змін | Зміни у вкладених об'єктах відображаються в обох копіях. | Копія повністю незалежна від оригіналу. |
- Поверхнева копія (Shallow Copy)
-
Object.assign:
const original = { a: 1, b: { c: 2 } }; const shallowCopy = Object.assign({}, original); shallowCopy.b.c = 42; console.log(original.b.c); // Виведе: 42
-
Spread-оператор:
const original = { a: 1, b: { c: 2 } }; const shallowCopy = { ...original }; shallowCopy.b.c = 42; console.log(original.b.c); // Виведе: 42
- Глибока копія (Deep Copy)
-
JSON (для об'єктів без функцій або посилань на інші об'єкти):
const original = { a: 1, b: { c: 2 } }; const deepCopy = JSON.parse(JSON.stringify(original)); deepCopy.b.c = 42; console.log(original.b.c); // Виведе: 2
-
Рекурсивна функція:
function deepCopy(obj) { if (obj === null || typeof obj !== "object") return obj; const copy = Array.isArray(obj) ? [] : {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { copy[key] = deepCopy(obj[key]); } } return copy; } const original = { a: 1, b: { c: 2 } }; const deepCopyObj = deepCopy(original); deepCopyObj.b.c = 42; console.log(original.b.c); // Виведе: 2
-
Бібліотека Lodash:
const _ = require("lodash"); const original = { a: 1, b: { c: 2 } }; const deepCopy = _.cloneDeep(original); deepCopy.b.c = 42; console.log(original.b.c); // Виведе: 2
-
Висновок:
- Використовуйте поверхневу копію, якщо об'єкт має лише верхній рівень властивостей.
- Застосовуйте глибоку копію, якщо потрібно копіювати вкладені структури, щоб уникнути побічних ефектів.
83. Що таке ланцюжок викликів функцій (chaining)?
- Ланцюжок викликів (chaining) — це техніка в JavaScript, яка дозволяє викликати кілька методів об'єкта послідовно в одному виразі. Це досягається завдяки поверненню самого об'єкта (
this
) у кожному методі, що дозволяє викликати наступний метод без створення нового рядка коду.
class Calculator {
constructor(value = 0) {
this.value = value;
}
add(number) {
this.value += number;
return this; // Повертаємо поточний об'єкт
}
subtract(number) {
this.value -= number;
return this; // Повертаємо поточний об'єкт
}
multiply(number) {
this.value *= number;
return this; // Повертаємо поточний об'єкт
}
divide(number) {
if (number !== 0) {
this.value /= number;
}
return this; // Повертаємо поточний об'єкт
}
getResult() {
return this.value;
}
}
const result = new Calculator()
.add(10)
.subtract(2)
.multiply(4)
.divide(2)
.getResult();
console.log(result); // Виведе: 16
-
Переваги:
-
Зменшує кількість змінних у коді.
-
Робить код компактнішим і легшим для читання.
-
-
Обмеження:
-
Усі методи повинні повертати об'єкт, на якому викликаються.
-
Код може стати менш зрозумілим у разі надмірного використання.
-
- Рядки:
const result = " JavaScript "
.trim()
.toUpperCase()
.replace("JAVASCRIPT", "CHAINING");
console.log(result); // Виведе: CHAINING
- Масиви:
const result = [1, 2, 3, 4, 5]
.filter((num) => num % 2 === 0)
.map((num) => num \* 2)
.reduce((sum, num) => sum + num, 0);
console.log(result); // Виведе: 12
- Ланцюжок викликів — потужна техніка, яка спрощує виконання послідовних операцій на одному об'єкті. Використовуйте її для покращення читабельності та скорочення коду.
84. Що таке неоголошена змінна?
- Неоголошена змінна (
undeclared variable
) — це змінна, яка використовується у коді без попереднього оголошення за допомогою ключових слівvar
,let
абоconst
.
- Якщо змінна не оголошена, але їй присвоюється значення, JavaScript автоматично створює її як глобальну змінну.
- У строгому режимі (
strict mode
) використання неоголошених змінних викликає помилку.
function example() {
x = 10; // Неоголошена змінна
console.log(x); // Виведе: 10
}
example();
console.log(x); // Виведе: 10 (глобальна змінна створена автоматично)
Приклад із strict mode:
"use strict";
function example() {
x = 10; // Помилка: x is not defined
}
example();
- Глобальна область видимості: Неоголошені змінні автоматично стають глобальними, що може призвести до конфліктів і помилок.
- Важко відстежити: Код стає менш передбачуваним і важчим для налагодження.
- Сумісність із strict mode: Використання строгого режиму допомагає уникнути неочікуваної поведінки.
- Завжди оголошуйте змінні явно за допомогою
let
,const
абоvar
:
function example() {
let x = 10; // Явно оголошена змінна
console.log(x); // Виведе: 10
}
example();
console.log(typeof x); // Виведе: undefined (x не є глобальною змінною)
- Неоголошені змінні можуть призвести до неочікуваної поведінки коду. Використовуйте
let
абоconst
для безпечного та передбачуваного коду, а також активуйте строгий режим (use strict
) для запобігання випадковому створенню неоголошених змінних.
85. Як передаються параметри у функцію: за посиланням чи значенням?
- У JavaScript параметри функції передаються або за значенням, або за посиланням, в залежності від типу переданого значення.
- Примітивні типи даних (наприклад,
number
,string
,boolean
,null
,undefined
,symbol
,bigint
) передаються за значенням. - Копія значення передається функції, і будь-які зміни цього значення всередині функції не впливають на початкову змінну.
function changeValue(a) {
a = 20;
}
let num = 10;
changeValue(num);
console.log(num); // Виведе: 10 (значення не змінюється)
- Об'єкти (включаючи масиви та функції) передаються за посиланням.
- Функція отримує посилання на оригінальний об'єкт, тому зміни всередині функції впливають на оригінальний об'єкт.
Копіювати код
function changeObject(obj) {
obj.name = "Alice";
}
let person = { name: "Bob" };
changeObject(person);
console.log(person.name); // Виведе: "Alice" (об'єкт змінено)
-
Примітиви: Примітивні значення є копіями самих себе, тому при їх передачі в функцію передається їх копія.
-
Об'єкти: Об'єкти в JavaScript зберігаються як посилання, тому при передачі об'єкта в функцію передається посилання на нього.
-
Примітиви передаються за значенням, тому зміни не впливають на оригінальне значення.
-
Об'єкти передаються за посиланням, тому зміни в функції змінюють оригінальний об'єкт.
86. Плюси та мінуси іммутабельності? Як досягти іммутабельності у JS?
Іммутабельність означає, що після створення об'єкт або значення не можуть бути змінені. Будь-яка зміна створює новий об'єкт або значення.
-
Простота налагодження:
- Легше відслідковувати зміни в коді, оскільки дані не змінюються.
-
Безпека:
- Зменшується ризик побічних ефектів через непередбачені зміни об'єктів.
-
Сумісність із функціональним програмуванням:
- Іммутабельність є основою функціонального підходу, що покращує читабельність і тестування коду.
-
Безпека багатопоточного виконання:
- У випадках, коли дані доступні кільком потокам, іммутабельні дані не потребують синхронізації.
-
Оптимізація продуктивності:
- Можна використовувати техніки мемоізації або порівняння "за посиланням" (
===
).
- Можна використовувати техніки мемоізації або порівняння "за посиланням" (
-
Витрати пам'яті:
- Кожна зміна створює нову копію об'єкта або масиву, що може збільшувати використання пам'яті.
-
Зниження продуктивності:
- Створення нових об'єктів і копіювання даних може бути повільнішим, ніж зміна існуючих об'єктів.
-
Ускладнення роботи:
- Іноді потрібні додаткові бібліотеки або техніки для підтримки іммутабельності (наприклад,
Immutable.js
).
- Іноді потрібні додаткові бібліотеки або техніки для підтримки іммутабельності (наприклад,
-
Для примітивів:
- Примітиви у JavaScript вже іммутабельні.
-
Для об'єктів:
- Використовуйте методи створення копій, такі як
Object.assign
або спред-оператор.
- Використовуйте методи створення копій, такі як
const original = { name: "Alice", age: 25 };
const copy = { ...original, age: 30 };
console.log(original); // { name: "Alice", age: 25 }
console.log(copy); // { name: "Alice", age: 30 }
- Для масивів:
-
Використовуйте методи, які не змінюють оригінальний масив (наприклад, map, filter, concat).
-
Приклад:
const original = [1, 2, 3];
const updated = [...original, 4];
console.log(original); // [1, 2, 3]
console.log(updated); // [1, 2, 3, 4]
- Використовуйте
Object.freeze
:
-
Заморожує об'єкт, забороняючи його зміну.
-
Приклад:
const frozen = Object.freeze({ name: "Alice" });
frozen.name = "Bob"; // Не змінить значення, у суворому режимі викличе помилку
console.log(frozen); // { name: "Alice" }
- Застосовуйте бібліотеки:
- Використовуйте спеціалізовані бібліотеки для роботи з іммутабельними структурами даних (наприклад, Immutable.js або Immer).
- Іммутабельність робить код передбачуванішим і безпечнішим, але може збільшувати використання пам'яті та ускладнювати роботу. Її доцільно використовувати, коли важливі чистота даних, багатопотоковість або функціональний підхід.
87. Типи спливаючих вікон JavaScript?
- JavaScript підтримує три основні типи спливаючих вікон для взаємодії з користувачем:
alert
- Використовується для відображення простого повідомлення.
- Не дозволяє взаємодію з рештою сторінки, поки користувач не закриє вікно.
alert("Це інформаційне повідомлення.");
confirm
- Використовується для підтвердження дії користувачем.
- Повертає true, якщо користувач натиснув "OK", і false, якщо натиснув "Cancel".
if (confirm("Ви впевнені?")) {
console.log("Користувач підтвердив.");
} else {
console.log("Користувач скасував.");
}
prompt
- Дозволяє користувачеві ввести текст.
- Повертає введений текст, або null, якщо користувач натиснув "Cancel".
const name = prompt("Введіть ваше ім'я:");
if (name) {
console.log(`Привіт, ${name}!`);
} else {
console.log("Користувач нічого не ввів.");
}
- Ці методи є синхронними: блокують виконання коду, поки користувач не взаємодіє з вікном.
- Їх не рекомендується використовувати у сучасних веб-додатках через негативний вплив на UX.
- Краще використовувати кастомні модальні вікна, реалізовані на HTML, CSS і JavaScript, для кращого контролю над зовнішнім виглядом і поведінкою.
88. Типи об'єктів JavaScript?
- У JavaScript існують різні типи об'єктів, які можна класифікувати наступним чином:
- Нативні об'єкти (Native Objects)
-
Це вбудовані об'єкти, визначені стандартом ECMAScript.
-
Приклади:
Object
Array
Function
Date
RegExp
Error
Promise
- Глобальні об'єкти (Global Objects)
-
Доступні в будь-якому контексті без необхідності створення чи імпорту.
-
Приклади:
Math
JSON
console
globalThis
- Об'єкти середовища виконання (Host Objects)
-
Надаються середовищем виконання (браузер або Node.js).
-
Браузер:
window
document
HTMLElement
localStorage
-
Node.js:
process
Buffer
require
- Користувацькі об'єкти (User-Defined Objects)
- Об'єкти, створені користувачем вручну.
const user = {
name: "Alice",
age: 25,
greet() {
console.log(`Привіт, я ${this.name}`);
},
};
- Спеціалізовані об'єкти (Specialized Objects)
-
Це об'єкти, створені через функції-конструктори або класи.
-
Приклади:
Map
,Set
,WeakMap
,WeakSet
Int8Array
,Uint8Array
,ArrayBuffer
Symbol
-
-
Прототипні об'єкти (Prototype Objects)
- Об'єкти, які слугують прототипами для інших об'єктів.
- Всі об'єкти мають властивість [[Prototype]], яку можна отримати через Object.getPrototypeOf() або proto.
- Приклад:
const parent = {
greet() {
console.log("Привіт");
},
};
const child = Object.create(parent);
child.greet(); // "Привіт"
Тип об'єкта | Приклади |
---|---|
Нативні | Object , Array , Date , Promise |
Глобальні | Math , JSON , console , globalThis |
Об'єкти середовища | window , document , process , Buffer |
Користувацькі | Об'єкти, створені вручну |
Спеціалізовані | Map , Set , ArrayBuffer , Symbol |
Прототипні | Object.prototype , кастомні прототипи |
89. Парадигми програмування JavaScript?
JavaScript підтримує кілька парадигм програмування, що робить його потужною мовою для різних завдань.
Парадигма | Опис |
---|---|
Імперативне програмування | Фокус на покроковому описі логіки виконання. Код визначає, як виконувати задачу. |
Декларативне програмування | Замість опису, як виконувати задачу, описується, що має бути виконано. Приклад: маніпуляції DOM за допомогою бібліотек (React, Vue). |
Об'єктно-орієнтоване | Організація коду навколо об'єктів, що мають властивості та методи. Підтримується прототипне наслідування. |
Функціональне | Використання функцій як першокласних об'єктів, уникання змінюваних даних, чисті функції, каррінг, композиція функцій. |
Асинхронне | Обробка асинхронного коду через колбеки, проміси, async/await , що дозволяє ефективно працювати з I/O операціями та таймерами. |
Реактивне | Обробка потоків даних у реальному часі за допомогою бібліотек, таких як RxJS, через стріми, спостережувані об'єкти, оператори трансформацій. |
Подієво-орієнтоване | Використання подій і їх обробників, що є основою браузерного середовища (наприклад, addEventListener , onClick ). |
Примітка: JavaScript гнучко підтримує кілька парадигм одночасно, що дозволяє використовувати найзручніший підхід для конкретного завдання.
90. Типи помилок у JavaScript?
- У JavaScript існує кілька типів помилок, які можуть виникати під час виконання коду:
Тип помилки | Опис | Приклад |
---|---|---|
SyntaxError | Виникає, коли код містить синтаксичну помилку, яка унеможливлює виконання. | javascript<br>console.log("Привіт); // SyntaxError: missing " after argument<br> |
ReferenceError | Виникає, коли код звертається до змінної, яка не оголошена. | javascript<br>console.log(x); // ReferenceError: x is not defined<br> |
TypeError | Виникає, коли виконується операція над значенням некоректного типу. | javascript<br>null.toString(); // TypeError: Cannot read properties of null<br> |
RangeError | Виникає, коли значення виходить за допустимі межі. | javascript<br>let arr = new Array(-1); // RangeError: Invalid array length<br> |
EvalError | Пов'язана з некоректним використанням функції eval . У сучасному JavaScript використовується рідко. |
javascript<br>eval("let a = ;"); // EvalError: Unexpected end of input<br> |
URIError | Виникає, коли некоректно використовується функція для роботи з URI (наприклад, decodeURI ). |
javascript<br>decodeURI("%"); // URIError: URI malformed<br> |
- Для обробки помилок використовується конструкція
try...catch
:
try {
const result = JSON.parse("Некоректний JSON");
} catch (error) {
console.error("Сталася помилка:", error.message);
}
91. Різниця між typeof і instanceof?
Критерій | typeof | instanceof |
---|---|---|
Призначення | Повертає тип змінної як рядок. | Перевіряє, чи є об'єкт екземпляром певного класу або конструктора. |
Результат | Повертає один із базових типів (string , number , object , тощо). |
Повертає true або false . |
Сфера застосування | Використовується для визначення типу даних. | Використовується для перевірки приналежності об'єкта до класу або прототипу. |
Обмеження | Не відрізняє масиви від об'єктів (typeof [] повертає object ). |
Працює тільки з об'єктами, створеними через функції-конструктори. |
console.log(typeof "Hello"); // "string"
console.log(typeof 42); // "number"
console.log(typeof {}); // "object"
console.log(typeof []); // "object" (масиви не розрізняються)
console.log(typeof null); // "object" (історична помилка)
console.log(typeof undefined); // "undefined"
const arr = [];
console.log(arr instanceof Array); // true
console.log(arr instanceof Object); // true (Array наслідується від Object)
const str = new String("Hello");
console.log(str instanceof String); // true
console.log(str instanceof Object); // true
console.log("Hello" instanceof String); // false (рядок — примітив)
- Примітиви:
typeof
працює з примітивними типами.instanceof
завжди повертаєfalse
для примітивів.
- Масиви:
typeof []
повертає"object"
.[] instanceof Array
повертаєtrue
.
- null і undefined:
-
typeof null
повертає"object"
(історична помилка в JS). -
null instanceof Object
повертаєfalse
. -
undefined
не має конструктора, томуinstanceof
не використовується.- Використовуйте
typeof
для перевірки типу примітивів і базових типів, аinstanceof
для перевірки класів і об'єктів.
- Використовуйте
92. ???
- Coming soon...😎