1. Можете ли вы написать функцию, которая меняет порядок слов в предложении?

Представьте, что вам дано предложение «JavaScript is fun» («JavaScript — это весело»), в котором нужно изменить порядок слов. На выходе должно получиться «Fun is JavaScript” («Веселье — это JavaScript»).

Решение:

function reverseWords(sentence) {
    return sentence.split(' ').reverse().join(' ');
}
console.log(reverseWords("JavaScript is fun")); // Вывод: "fun is JavaScript"

Пошаговое объяснение

  1. Метод split(' ') разбивает предложение на массив слов с использованием пробелов. Например, "JavaScript is fun" превращается в ["JavaScript", "is", "fun"].
  1. Метод reverse() меняет порядок слов в массиве, так что получается ["fun", "is", "JavaScript"].
  1. Метод join(' ') объединяет слова в строку, добавляя между ними пробелы.

Зачем это нужно: задание проверяет навыки работы со строками и массивами, которые являются ключевыми в программировании на JavaScript.

2. Как создать промис, который ждет 2 секунды, прежде чем разрешиться?

Промис — своеобразный контейнер для будущего значения. В данном случае требуется создать промис, ожидающий 2 секунды, прежде чем будет отдана команда: «Done waiting!» («Ожидание завершить!»).

Решение:

function delayedMessage() {
    return new Promise((resolve) => {
        setTimeout(() => resolve("Done waiting!"), 2000);
    });
}

delayedMessage().then((message) => console.log(message)); // Вывод (после 2 секунд): "Done waiting!"

Пошаговое объяснение

  1.  Promise принимает функцию с параметром resolve.
  1. Находящаяся внутри промиса функция setTimeout ждет 2 секунды (2000 миллисекунд).
  1. Через 2 секунды вызывается функция resolve, и промис считается «выполненным» (или «разрешенным»).
  1. Метод .then() запускается, когда промис завершается, и записывает сообщение в консоль.

Зачем это нужно: промисы очень важны в JavaScript для обработки асинхронных задач, таких как получение данных или ожидание событий.

3. Как обрабатывать нажатия кнопок, созданных после загрузки страницы?

Иногда на страницу добавляются новые кнопки после ее загрузки. Нужно написать функцию, которая обрабатывает нажатия всех кнопок, даже если они появились позже.

Решение:

document.getElementById("container").addEventListener("click", (event) => {
    if (event.target.tagName === "BUTTON") {
        console.log(`Button clicked: ${event.target.textContent}`);
    }
});

Пошаговое объяснение

  1. Прикрепляем слушатель событий нажатий одним щелчком мыши к родительскому элементу, например div с ID container.
  2. Когда происходит нажатие, объект события (event) сообщает, что было нажато.
  1. Используем event.target.tagName, чтобы проверить, является ли нажатый элемент BUTTON (кнопкой).
  1. Если это так, делаем что-то вроде записи в журнал текстового контента кнопки.

Зачем это нужно: данный вопрос проверяет, знаете ли вы, что делегирование событий — разумный способ управлять событиями для динамически добавляемых элементов.

4. В чем разница между == и === в JavaScript?

Многие разработчики путают эти два оператора, поэтому на собеседовании любят спрашивать о них. Объясните разницу на примерах.

Решение:

console.log(5 == "5");  // Вывод: true
console.log(5 === "5"); // Вывод: false

Пошаговое объяснение

  1. == проверяет, одинаковы ли значения, но не учитывает тип. Например, 5 (число) и "5" (строка) считаются равными.
  1. === проверяет, одинаковы ли значение и тип. Здесь 5 (число) не равно "5" (строка), поэтому возвращается false.

Зачем это нужно: понимание этих различий помогает писать более качественный код, избегая неожиданных результатов, вызванных преобразованием типов.

5. Что такое замыкание в JavaScript? Напишите функцию, показывающую, как работает замыкание

Замыкание — важная концепция в JavaScript. Замыкание происходит, когда функция «запоминает» переменные родительской функции даже после того, как родительская функция завершила свое выполнение.

Решение:

function outerFunction(outerVariable) {
    return function innerFunction(innerVariable) {
        return `Outer: ${outerVariable}, Inner: ${innerVariable}`;
    };
}

const closure = outerFunction("outside");
console.log(closure("inside")); // Вывод: "Outer: outside, Inner: inside"

Пошаговое объяснение

  1. outerFunction принимает параметр (outerVariable) и возвращает новую функцию.
  1. innerFunction принимает свой собственный параметр (innerVariable) и использует как свои, так и родительские переменные.
  1. Даже после завершения работы outerFunction возвращаемая innerFunction сохраняет доступ к outerVariable.

Зачем это нужно: замыкания используются во многих реальных сценариях, таких как создание приватных переменных или создание многократно используемых функций.

6. Как JavaScript обрабатывает асинхронные задачи? Объясните это на примере

JavaScript использует так называемый цикл событий для обработки таких задач, как таймеры и вызовы API, не блокируя основную программу.

Решение:

console.log("Start");
setTimeout(() => console.log("Timeout"), 0);
console.log("End");
// Вывод: "Start", "End", "Timeout"

Пошаговое объяснение

  1. Когда программа запускается, "Start" регистрируется сразу, потому что это обычная задача.
  1. setTimeout назначает обратный вызов (console.log("Timeout")) на более позднее время и добавляет его в очередь событий.
  1. Событие "End" регистрируется, потому что все еще является частью основного кода.
  1. После завершения основного кода цикл событий проверяет очередь и запускает обратный вызов, регистрируя "Timeout".

Зачем это нужно: в данном вопросе проверяется понимание асинхронного JavaScript и цикла событий, которые являются ключевыми для современной веб-разработки.

7. Как работает прототипное наследование в JavaScript? Приведите пример прототипного наследования

Прототипное наследование позволяет объектам совместно использовать свойства и методы через цепочку прототипов.

Решение:

function Person(name) {
    this.name = name;
}
Person.prototype.greet = function() {
    return `Hello, my name is ${this.name}`;
};

const alice = new Person("Alice");
console.log(alice.greet()); // Вывод: "Hello, my name is Alice"

Пошаговое объяснение

  1. Person — функция-конструктор, которая присваивает свойство name создаваемому объекту.
  1. В Person.prototype добавляется метод greet. Все объекты Person могут использовать этот метод.
  1. Когда вызывается alice.greet(), JavaScript ищет greet в alice. Не найдя его напрямую, он поднимается по цепочке прототипов до Person.prototype и запускает метод.

Зачем это нужно: прототипное наследование — возможность объектов JavaScript повторно использовать код. Понимание механизма прототипного наследования позволяет писать эффективный, многократно используемый код.

Заключение

Изучив эти вопросы и ответы, вы будете лучше подготовлены к собеседованию по JavaScript. Разбирайте каждую проблему шаг за шагом, приучаясь объяснять ход своих мыслей.

У вас все получится!

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Arnold Gunter: If You Can Answer These 7 JavaScript Interview Questions, Companies Want To Hire You Immediately

Предыдущая статьяPalette: оживляем гибридные узлы Amazon EKS
Следующая статьяC++: практическое руководство по Transform