Часті питання та відповіді на співбесіді з JavaScript

Наявність знань JavaScript у вашому професійному портфоліо значно підвищує ваші шанси на отримання посади розробника програмного забезпечення. Розгляньмо детальніше, які типові питання можуть виникнути на співбесіді стосовно JavaScript.

JavaScript є однією з найбільш розповсюджених мов програмування у сфері веб-розробки. Сьогодні її застосовують для створення широкого спектру програмних продуктів.

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

JavaScript — це легка у використанні, інтерпретована або JIT-компільована мова програмування. Вона є однією з ключових мов для функціонування веб-простору. Звісно, існують ще дві фундаментальні мови World Wide Web. Якщо ви не знайомі з ними, рекомендую ознайомитися.

JavaScript спочатку розроблялася для веб-середовища, але на сьогодні її застосування набагато ширше. Завдяки таким платформам, як Node.js та Deno, ми можемо запускати JavaScript-код майже на будь-якій операційній системі.

Давайте поглянемо на деякі ключові переваги використання JavaScript:

Переваги JavaScript

  • Легкість у вивченні. Можна почати опановувати цю мову навіть без попереднього досвіду програмування.
  • Активна спільнота розробників. Ви завжди зможете знайти необхідну допомогу в разі труднощів.
  • Велика кількість бібліотек та фреймворків. Це дозволяє прискорити процес розробки програмних продуктів.
  • Універсальність. JavaScript дозволяє розробляти як фронтенд, так і бекенд, а також застосунки для Android, iOS тощо. За допомогою цієї мови можна створити майже будь-який тип програми. Проте, вона залишається найефективнішою саме у веб-розробці.

Які типи даних існують у JavaScript?

Типи даних використовуються для організації зберігання інформації різних видів. Набір типів даних відрізняється в різних мовах програмування. У JavaScript їх налічується 8. Розгляньмо кожен із них:

  • Число (Number)
  • Рядок (String)
  • Логічний (Boolean)
  • Невизначений (Undefined)
  • Нульовий (Null)
  • Велике ціле число (BigInt)
  • Символ (Symbol)
  • Об’єкт (Object)

Всі типи даних, за винятком Object, є примітивними значеннями та є незмінними.

Які вбудовані методи доступні в JavaScript?

В JavaScript кожен тип даних має свій набір вбудованих методів. Доступ до цих методів здійснюється через відповідний тип даних. Розглянемо деякі приклади вбудованих методів для різних типів даних та структур:

  • Число (Number)
  • Рядок (String)
    • toLowerCase
    • startsWith
    • charAt
  • Масив (Array)
  • Існує велика кількість вбудованих методів для кожного типу даних. Рекомендується переглянути повний перелік вбудованих методів для різних типів даних та структур.

    Як створити масив у JavaScript?

    Масиви є однією з основних структур даних в JavaScript. Вони можуть містити дані різних типів, оскільки JavaScript є динамічно типізованою мовою. Розглянемо методи створення масивів в JavaScript.

    Масив можна створити за допомогою квадратних дужок []. Цей спосіб є простим і швидким:

      // Створення порожнього масиву
      const arr = [];
    
      // Створення масиву з випадковими значеннями
      const randomArr = [1, "Один", true];
    
      console.log(arr, randomArr);
    

    Іншим способом є використання конструктора Array. Проте цей метод рідко використовується у звичайних проектах.

      // Створення порожнього масиву
      const arr = new Array();
    
      // Створення масиву з випадковими значеннями
      const randomArr = new Array(1, "Один", true);
    
      console.log(arr, randomArr);
    

    Масиви в JavaScript є змінними, тобто їх можна модифікувати після створення.

    Як створити об’єкт в JavaScript?

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

    Об’єкт можна створити за допомогою фігурних дужок {}. Це простий і швидкий спосіб:

      // Створення порожнього об’єкта
      const object = {};
    
      // Створення об’єкта з випадковими значеннями
      const randomObject = { 1: 2, one: "Two", true: false };
    
      console.log(object, randomObject);
    

    Іншим способом є використання конструктора Object. Він рідко використовується в реальних проектах.

      // Створення порожнього об’єкта
      const object = new Object();
    
      // Створення об’єкта з випадковими значеннями
      const randomObject = new Object();
      randomObject[1] = 2;
      randomObject["one"] = "Two";
      randomObject[true] = false;
    
      console.log(object, randomObject);
    

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

    Як налагоджувати код JavaScript?

    Налагодження коду – непросте завдання. Підходи до налагодження можуть відрізнятися залежно від мови програмування, проекту та інших факторів. Розглянемо, які методи часто використовуються для налагодження JavaScript-коду.

    1. Логування

    Для виявлення помилок можна використовувати оператори console.log у різних частинах коду. Якщо в попередньому рядку коду є помилка, виконання наступних рядків коду буде зупинено.

    Логування є одним із старих методів налагодження, який є досить ефективним для невеликих проектів. Це стандартна техніка налагодження для будь-якої мови програмування.

    2. Інструменти розробника

    JavaScript переважно використовується для розробки веб-додатків. Тому майже всі браузери мають вбудовані інструменти розробника, які допомагають налагоджувати JavaScript-код.

    Одним із найпопулярніших методів налагодження є встановлення точок зупинки в інструментах розробника. Точки зупинки призупиняють виконання JavaScript-коду та надають повну інформацію про стан виконання на цей момент.

    Можна встановити кілька точок зупинки в місцях, де виникають помилки, щоб зрозуміти причину їх появи. Це є дуже ефективним способом налагодження веб-додатків JavaScript.

    3. Інтегровані середовища розробки (IDE)

    IDE також можна використовувати для налагодження JavaScript-коду. Наприклад, VS Code підтримує налагодження за допомогою точок зупинки. Функціональність налагодження може відрізнятися залежно від IDE, яку ви використовуєте, але більшість з них мають цю можливість.

    Як додати код JavaScript у HTML-файл?

    JavaScript-код в HTML-файл додається за допомогою тегу <script>. Нижче наведено приклад:

    <html lang="uk">
      <head>
        <title>techukraine.net</title>
      </head>
      <body>
        <h2>techukraine.net</h2>
    
        <script>
          // Тут розміщується JavaScript-код
          console.log("Це JavaScript-код");
        </script>
      </body>
    </html>
    

    Що таке файли cookie?

    Файли cookie — це пари ключ-значення, що використовуються для зберігання невеликих обсягів інформації. Інформація може бути будь-якою. Файли cookie можуть мати термін дії, після якого вони будуть автоматично видалені. Вони широко застосовуються для зберігання інформації про користувача.

    Файли cookie не видаляються навіть після оновлення сторінки, доки вони не будуть видалені вручну або доки не закінчиться термін їхньої дії. Ви можете переглянути файли cookie будь-якого веб-застосунку/веб-сторінки, відкривши інструменти розробника в браузері.

    Як прочитати файл cookie?

    В JavaScript файл cookie можна прочитати за допомогою властивості document.cookie. Вона повертає усі створені файли cookie.

    console.log("Усі файли cookie", document.cookie);
    

    Якщо файлів cookie немає, то вона поверне порожній рядок.

    Як створити і видалити файл cookie?

    Файл cookie створюється шляхом встановлення пари ключ-значення для document.cookie. Ось приклад:

    document.cookie = "один=Один;";
    

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

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

    document.cookie = "один=Один;expires=Jan 31 2024;path=/;";
    

    У цьому прикладі ми додали термін дії та шлях до файлу cookie. Якщо термін дії не вказано, файл cookie буде видалено після завершення сеансу. За замовчуванням шлях файлу cookie збігається зі шляхом файлу, що його створив. Формат терміну дії повинен бути у GMT.

    Погляньмо, як створити кілька файлів cookie:

    document.cookie = "один=Один;expires=Jan 31 2024;path=/;";
    document.cookie = "два=Два;expires=Jan 31 2024;path=/;";
    document.cookie = "три=Три;expires=Jan 31 2024;path=/;";
    

    Файли cookie не будуть перезаписані, якщо при створенні кількох файлів cookie відрізняються ключ або шлях. Якщо ключ і шлях збігаються, попередній файл cookie буде перезаписано. Наступний приклад перезапише попередньо встановлений файл cookie:

    document.cookie = "один=Один;expires=Jan 31 2024;path=/;";
    document.cookie = "один=Два;path=/;";
    

    У наведеному прикладі видалено термін дії файлу cookie і змінено його значення.

    Під час тестування коду використовуйте дату, яка настає у майбутньому. Якщо ви встановите однакову дату, як 31 січня 2024 року навіть після 31 січня 2024 року, файли cookie не будуть створені.

    Ми розглянули, як створювати та оновлювати файли cookie. Тепер розглянемо, як їх видалити.

    Видалити файл cookie легко: потрібно встановити термін дії на будь-яку минулу дату. Розглянемо приклад:

    // Створення файлів cookie
    document.cookie = "один=Один;expires=Jan 31 2024;path=/;";
    document.cookie = "два=Два;expires=Jan 31 2024;path=/;";
    document.cookie = "три=Три;expires=Jan 31 2024;path=/;";
    
    // Видалення останнього файлу cookie
    document.cookie = "три=Три;expires=Jan 1 2024;path=/;";
    

    Ви не знайдете останній файл cookie у списку файлів cookie, оскільки він був видалений в останньому рядку коду. Це і є короткий посібник із файлів cookie.

    Які існують різні фреймворки JavaScript?

    Існує велика кількість JavaScript-фреймворків. React, Vue, Angular призначені для розробки інтерфейсу користувача. Express, Koa, Nest використовуються для розробки серверної частини. NextJS, Gatsby застосовують для створення статичних сайтів. React Native, Ionic використовують для розробки мобільних застосунків. Ми згадали лише деякі з фреймворків JavaScript. Ви можете знайти набагато більше фреймворків, на вивчення яких потрібно буде витратити багато часу. Досліджуйте їх у міру необхідності.

    Замикання в JavaScript

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

    function outer() {
      const a = 1;
      function inner() {
        // Ми можемо отримати доступ до всіх даних із зовнішньої області видимості
        // Дані будуть доступні, навіть якщо ми виконаємо цю функцію за межами зовнішньої функції
        // Оскільки замикання inner було створено під час її оголошення
        console.log("Доступ до a в inner", a);
      }
      return inner;
    }
    
    const innerFn = outer();
    innerFn();
    

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

    Підняття в JavaScript

    Підняття (hoisting) – це процес, при якому оголошення змінних, функцій і класів переміщуються до початку області їх видимості до початку виконання коду.

    // Доступ до `name` до її оголошення
    console.log(name);
    
    // Оголошення та ініціалізація `name`
    var name = "techukraine.net";
    

    Якщо запустити цей код, ви не побачите жодної помилки. Однак, у більшості мов програмування ви отримали б помилку. Результатом буде невизначене значення, оскільки підняття переміщує лише оголошення вгору, але ініціалізація відбудеться лише в рядку 3.

    Замініть var на let або const і запустіть код ще раз.

    // Доступ до `name` до її оголошення
    console.log(name);
    
    // Оголошення та ініціалізація `name`
    const name = "techukraine.net";
    

    Тепер ви отримаєте помилку, що повідомляє про неможливість доступу до змінної до її ініціалізації.

    ReferenceError: Неможливо отримати доступ до 'name' до ініціалізації
    

    Таким чином, let і const, введені в ES6, забороняють доступ до змінної до її ініціалізації, як видно з повідомлення про помилку. Це пов’язано з тим, що змінні, оголошені за допомогою let або const, знаходяться у тимчасовій мертвій зоні (TDZ) до моменту їх ініціалізації. Ми не можемо отримати доступ до змінних з TDZ.

    Каррінг в JavaScript

    Каррінг — це метод перетворення функцій із кількома параметрами на функції з одним параметром, викликані послідовно. Завдяки каррінгу ми можемо перетворити функцію add(a, b, c, d) на виклик add(a)(b)(c)(d). Подивимося на прикладі, як це зробити.

    function getCurryCallback(callback) {
      return function (a) {
        return function (b) {
          return function (c) {
            return function (d) {
              return callback(a, b, c, d);
            };
          };
        };
      };
    }
    
    function add(a, b, c, d) {
      return a + b + c + d;
    }
    
    const curriedAdd = getCurryCallback(add);
    
    // Виклик curriedAdd
    console.log(curriedAdd(1)(2)(3)(4));
    

    Ми можемо узагальнити функцію getCurryCallback, щоб її можна було використовувати для перетворення різних функцій на карріровані виклики. Щоб дізнатися більше про це, можна звернутися до посібників з JavaScript.

    Різниця між об’єктами document і window

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

    Об’єкт document є частиною об’єкта window. Весь HTML-код, що завантажується на веб-сторінку, перетворюється на об’єкт document. Об’єкт document є спеціальним елементом HTMLDocument, який має різні властивості та методи, як і всі елементи HTML.

    Об’єкт window представляє вікно браузера, а об’єкт document – HTML-документ, завантажений у вікні браузера.

    Різниця між клієнтською та серверною частинами

    Клієнтська сторона відноситься до кінцевого користувача, який використовує застосунок. Серверна сторона відноситься до веб-сервера, на якому розгорнуто застосунок.

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

    Різниця між innerHTML та innerText

    innerHTML та innerText є властивостями HTML-елементів. За їх допомогою можна змінювати вміст HTML-елементів.

    Властивості innerHTML можна присвоїти рядок HTML, який буде відображений як звичайний HTML. Розглянемо приклад:

    const titleEl = document.getElementById("title");
    
    titleEl.innerHTML = '<span style="color:orange;">techukraine.net</span>';
    

    Додайте елемент з id “title” до вашого HTML та додайте вищенаведений код до JavaScript-файлу. Запустіть код і подивіться на результат. Ви побачите techukraine.net, виведеним помаранчевим кольором. Якщо перевірити елемент, він буде всередині тегу <span>. Таким чином, innerHTML сприйме HTML-рядок і відобразить його як звичайний HTML.

    InnerText, з іншого боку, сприйме звичайний рядок та відобразить його саме так, як він є. Він не відображатиме жодного HTML, як це робить innerHTML. Замініть innerHTML на innerText у вищенаведеному коді і погляньте на результат.

    const titleEl = document.getElementById("title");
    
    titleEl.innerText="<span style='color:orange;'>techukraine.net</span>";
    

    Тепер ви побачите точний рядок, який ми надали, на веб-сторінці.

    Різниця між let та var

    Ключові слова let і var використовуються для створення змінних у JavaScript. Ключове слово let було введено в ES6.

    Змінні, оголошені за допомогою let, мають блочну область видимості, тоді як змінні, оголошені за допомогою var, мають функціональну область видимості.

    {
      let a = 2;
      console.log("Всередині блоку", a);
    }
    console.log("Зовні блоку", a);
    

    Запустіть наведений вище код. Ви отримаєте помилку в останньому рядку, оскільки ми не можемо отримати доступ до let за межами блоку. Тепер замініть let на var і запустіть код знову.

    {
      var a = 2;
      console.log("Всередині блоку", a);
    }
    console.log("Зовні блоку", a);
    

    Ви не отримаєте жодної помилки, оскільки ми можемо отримати доступ до змінної a і за межами блоку. Тепер давайте замінимо блок функцією.

    function sample() {
      var a = 2;
      console.log("Всередині функції", a);
    }
    sample();
    console.log("Зовні функції", a);
    

    Ви отримаєте помилку, оскільки ми не можемо отримати доступ до var a за межами функції, тому що це функціональна область видимості.

    Ми можемо переоголосити змінні за допомогою ключового слова var, але не можемо переоголосити змінні за допомогою ключового слова let. Розглянемо приклад.

    var a = "techukraine.net";
    var a = "Chandan";
    console.log(a);
    
    let a = "techukraine.net";
    let a = "Chandan";
    console.log(a);
    

    Перший фрагмент коду не викликає жодної помилки, а значення a буде змінено на останнє присвоєне значення. Другий фрагмент коду видасть помилку, оскільки ми не можемо повторно оголошувати змінні за допомогою let.

    Різниця між Session Storage та Local Storage

    Session Storage і Local Storage використовуються для зберігання інформації на комп’ютерах користувачів, до якої можна отримати доступ без підключення до Інтернету. Як у session storage, так і в local storage можна зберігати пари ключ-значення. І ключ, і значення буде перетворено на рядки, якщо ви вкажете будь-який інший тип даних або структуру.

    Session storage буде очищено після закінчення сеансу (коли браузер закрито). Local storage не буде очищено, поки ми самі його не очистимо.

    Доступ, оновлення та видалення session storage та local storage здійснюються за допомогою об’єктів sessionStorage і localStorage відповідно.

    Що таке NaN в JavaScript?

    NaN – це скорочення від Not-a-Number (не число). Це означає, що якесь значення не є коректним числом в JavaScript. NaN виникає в таких випадках, як 0/0, undefined * 2, 1 + undefined, null * undefined тощо.

    Що таке лексична область видимості?

    Лексична область видимості визначається місцем, де оголошено змінну, і вона дозволяє внутрішнім функціям отримувати доступ до змінних з батьківської області видимості. Припустімо, у нас є функція з двома вкладеними функціями. Внутрішня функція має доступ до змінних області видимості обох її батьківських функцій. Аналогічно, функція другого рівня має доступ до змінних зовнішньої функції. Розглянемо приклад:

    function outermost() {
      let a = 1;
      console.log(a);
      function middle() {
        let b = 2;
        // `a` доступна тут
        console.log(a, b);
        function innermost() {
          let c = 3;
          // `a` і `b` доступні тут
          console.log(a, b, c);
        }
        innermost();
      }
      middle();
    }
    outermost();
    

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

    Що означає передача за значенням і передача за посиланням?

    Передача за значенням і передача за посиланням – це два способи передачі аргументів до функцій в JavaScript.

    Передача за значенням: створює копію вихідних даних і передає її до функції. Таким чином, зміни, зроблені всередині функції, не вплинуть на оригінальні дані. Розглянемо приклад:

    function sample(a) {
      // Зміна значення `a`
      a = 5;
      console.log("Всередині функції", a);
    }
    let a = 3;
    sample(a);
    console.log("Зовні функції", a);
    

    Ви побачите, що вихідне значення a не змінилося, навіть якщо ми змінили його всередині функції.

    Передача за посиланням: передає посилання на дані до функції. Тому, будь-які зміни, зроблені всередині функції, також змінять вихідні дані.

    function sample(arr) {
      // Додавання нового значення до масиву
      arr.push(3);
      console.log("Всередині функції", arr);
    }
    let arr = [1, 2];
    sample(arr);
    console.log("Зовні функції", arr);
    

    Ви побачите, що вихідне значення arr змінилося, коли ми змінили його всередині функції.

    Примітка: всі примітивні типи даних передаються за значенням, а непримітивні – за посиланням.

    Що таке мемоізація?

    Мемоізація — це метод, який зберігає обчислені значення в кешах і використовує їх повторно, щоб не проводити обчислення знову. Це пришвидшує виконання коду, особливо коли обчислення є ресурсоємними. Зберігання даних займає додаткове місце, але це незначна проблема у порівнянні з часом виконання.

    const memo = {};
    function add(a, b) {
      const key = `${a}-${b}`;
    
      // Перевіряємо, чи обчислювали ми значення раніше
      if (memo[key]) {
        console.log("Не обчислюємо знову");
        return memo[key];
      }
    
      // Додаємо обчислене значення в кеш
      // Тут кеш – це простий глобальний об'єкт
      memo[key] = a + b;
      return memo[key];
    }
    
    console.log(add(1, 2));
    console.log(add(2, 3));
    console.log(add(1, 2));
    

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

    Що таке rest-параметр?

    Rest-параметр використовується для збору всіх решти параметрів у функції. Припустімо, у нас є функція, яка приймає щонайменше 2 аргументи, але може приймати максимум будь-яку кількість параметрів. У такому випадку ми можемо зібрати перші 2 параметри у звичайні змінні, а всі інші – за допомогою rest-параметра.

    function sample(a, b, ...rest) {
      console.log("Rest-параметр", rest);
    }
    
    sample(1, 2, 3, 4, 5);
    

    Rest-параметр буде масивом останніх трьох аргументів у наведеному вище прикладі. Завдяки цьому ми можемо мати будь-яку кількість параметрів для функції.

    Одна функція може мати лише один rest-параметр. Rest-параметр повинен бути останнім у списку параметрів.

    Що таке деструктуризація об’єкта?

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

    const object = { a: 1, b: 2, c: 3 };
    
    // Деструктуризація об'єкта
    const { a, b, c } = object;
    
    // Тепер a, b, c можна використовувати як звичайні змінні
    console.log(a, b, c);
    

    Ми можемо змінити імена змінних деструктуризованих змінних у тому самому рядку наступним чином.

    const object = { a: 1, b: 2, c: 3 };
    
    // Зміна імен `a` та `b`
    const { a: changedA, b: changedB, c } = object;
    
    // Тепер changedA, changedB, c можна використовувати як звичайні змінні
    console.log(changedA, changedB, c);
    

    Що таке деструктуризація масиву?

    Деструктуризація масиву використовується для доступу до змінних з масиву та присвоєння їх змінним. Розглянемо приклад.

    const array = [1, 2, 3];
    
    // Деструктуризація масиву
    // Вона базується на індексі масиву
    const [a, b, c] = array;
    
    // Тепер можна використовувати a, b, c як звичайні змінні
    console.log(a, b, c);
    

    Що таке захоплення подій та спливання подій?

    Захоплення подій та спливання подій — це два