7 вопросов для собеседования о замыкание в JavaScript. Сможете ли вы на них ответить?

Каждый разработчик JavaScript должен знать, что такое замыкание. Практически на каждом собеседования на позицию веб разработчика сплывает вопрос о концепции замыкания.

Я составил список из 7 интересных и более менее сложных вопросов о замыкание в JavaScript.

Возьмите карандаш и лист бумаги и попробуйте ответить на эти вопросы, не глядя на ответы и не запуская код. По моим оценкам, вам потребуется около 30 минут. Ответы буду в конце статьи.

Have fun!

Если вам нужно обновить знания о концепции замыкания, я рекомендую прочесть A Simple Explanation of JavaScript Closures.

Вопрос 1: найти замыкание

Рассмотрим следующие функции clickHandlerinventory и delayedReload:

let countClicks = 0;

button.addEventListener(‘click’, function clickHandler() {

countClicks++;

});

const result = (function immediate(number) {

const message = `number is: ${number}`;

return message;

})(100);

setTimeout(function delayedReload() {

location.reload();

}, 1000);

Какая из этих трех функций является замыканием и использует переменные из внешней области видимости?

Вопрос 2: потеряться в параметрах

Что будет выведено в консоль, в следующем фрагменте кода:

(function immediateA(a) {

return (function immediateB(b) {

console.log(a); // What is logged?

})(1);

})(0);

Вопрос 3: кто есть кто

Что будет выведено в консоль, в следующем фрагменте кода:

let count = 0;

(function immediate() {

if (count === 0) {

let count = 1;

console.log(count); // What is logged?

}

console.log(count); // What is logged?

})();

Вопрос 4: хитрое замыкание

Что будет выведено в консоль, в следующем фрагменте кода:

for (var i = 0; i < 3; i++) {

setTimeout(function log() {

console.log(i); // What is logged?

}, 1000);

}

Вопрос 5: правильное или неправильное сообщение

Что будет выведено в консоль, в следующем фрагменте кода:

function createIncrement() {

let count = 0;

function increment() {

count++;

}

let message = `Count is ${count}`;

function log() {

console.log(message);

}

return [increment, log];

}

const [increment, log] = createIncrement();

increment();

increment();

increment();

log(); // What is logged?

Вопрос 6: восстановить инкапсуляцию

Следующая функция createStack () создает структуру данных типа стек:

function createStack() {

return {

items: [],

push(item) {

this.items.push(item);

},

pop() {

return this.items.pop();

}

};

}

const stack = createStack();

stack.push(10);

stack.push(5);

stack.pop(); // => 5

stack.items; // => [10]

stack.items = [10, 100, 1000]; // Encapsulation broken!

Стек работает должным образом, но с одной небольшой проблемой. Любой может изменить массив элементов напрямую, потому что свойство stack.items открыто для изменения.

Это проблема, поскольку это нарушает инкапсуляцию: так как только методы push () и pop () должны быть общедоступными, а stack.items не должен быть доступен снаружи.

Выполните рефакторинг приведенной выше реализации стека, используя концепцию замыкания, чтобы не было возможности получить доступ к массиву элементов stack.items за пределами области действия функции createStack ():

function createStack() {

// Write your code here…

}

const stack = createStack();

stack.push(10);

stack.push(5);

stack.pop(); // => 5

stack.items; // => undefined

Вопрос 7: умное умножение

Напишите функцию multiply (), которая умножает 2 числа:

function multiply(num1, num2) {

// Write your code here…

}

Если multiply (num1, numb2) вызывается с 2 аргументами, она должна вернуть умножение этих двух аргументов.

Но если вызывается с одни аргументом const anotherFunc = multiply (num1), функция должна возвращать другую функцию. Возвращенная функция при вызове anotherFunc (num2) должна выполнить умножение num1 * num2.

multiply(4, 5); // => 20

multiply(3, 3); // => 9

const double = multiply(2);

double(5); // => 10

double(11); // => 22

Ответы на вопросы

Вопрос 1: найти замыкание

xcraft.ru

AD

Начни жизнь на одинокой планете

etvnet.com

AD

Сериалы, кино и ТВ в хорошем качестве

  1. clickHandler создает замыкание с переменной countClicks из внешней области.
  2. immediate не является замыканием, потому что не имеет доступа ни к каким переменным из внешней области.
  3. delayedReload создает замыкание из-за использования переменной, из глобальной области (также известной как внешняя область).

Вопрос 2: потеряться в параметрах

В консоль выводится 0. 

immediateA вызывается с аргументом 0, поэтому параметр равен 0.

Функция immediateB, вложенная в функцию immediateA , и представляет собой замыкание, которое захватывает переменную из внешней области immediateA , где а равно 0. Таким образом, console.log (а) выводит 0.

Вопрос 3: кто есть кто

В консоль выводится 1 и 0.

Первый оператор let count = 0 объявляет переменную count.

immediate() — это замыкание, которое захватывает переменную count из внешней области видимости. Внутри области видимости функции immediate() count равен 0.

Однако внутри условного выражения другое let count = 1 объявляет локальную переменную count, который перезаписывает count из внешней области. Первый console.log (count) выводит 1.

Второй console.log (count) выводит 0, поскольку здесь доступ к переменной count осуществляется из внешней области.

Вопрос 4: хитрое замыкание

В консоль выводится 3, 3, 3 .

Данный фрагмент кода выполняется в 2 этапа.

Этап 1

  1. for () повторяется 3 раза. Во время каждой итерации создается новая функция log (), которая фиксирует переменную isetTimout () планирует выполнение log () через 1000 мс.
  2. Когда цикл for () завершается, переменная i имеет значение 3.

Этап 2

Вторая фаза происходит через 1000 мс:

  1. setTimeout() выполняет запланированные функции log ()log () считывает текущее значение переменной i, которое на данный момент равно 3, и выводит в консоль 3.

Вот почему в консле 3, 3, 3 регистрируются в консоли.

Дополнительный вопрос: как бы вы исправили этот пример, чтобы записать значения 0, 1, 2?

Вопрос 5: правильное или неправильное сообщение

В консоль выводится 'Count is 0'.

Функция increment () была вызвана 3 раза, увеличивая Count до значения 3.

переменная message существует в рамках функции createIncrement (). Его начальное значение — «Count is 0». Однако, даже если переменная count была увеличена несколько раз, переменная message все еще содержит значение «Count is 0».

Функция log () — это замыкание, которое захватывает переменную message из области createIncrement (). В итоге console.log (message) выводит «Count is 0».

Дополнительный вопрос: как бы вы исправили функцию log (), чтобы она возвращала сообщение, имеющее фактическое значение счетчика? Напишите свое решение в комментарии ниже!

Вопрос 6: восстановить инкапсуляцию

Вот возможный рефакторинг createStack ():

function createStack() {

const items = [];

return {

push(item) {

items.push(item);

},

pop() {

return items.pop();

}

};

}

const stack = createStack();

stack.push(10);

stack.push(5);

stack.pop(); // => 5

stack.items; // => undefined

Переменную items переместили в внутрь области createStack ().

Благодаря этому изменению вне области createStack () нет возможности получить доступ или изменить массив items. Теперь items является приватной переменной: общедоступными являются только методы push () и pop ().

Методы push () и pop (), являясь замыканием, захватывают переменную элементов из области действия функции createStack ().

Вопрос 7: умное умножение

Вот возможная реализация функции multiply ():

function multiply(number1, number2) {

if (number2 !== undefined) {

return number1 * number2;

}

return function doMultiply(number2) {

return number1 * number2;

};

}

multiply(4, 5); // => 20

multiply(3, 3); // => 9

const double = multiply(2);

double(5); // => 10

double(11); // => 22

Если параметр number2 не является undefined, функция просто возвращает number1 * number2.

Но если number2 undefined, это означает, что функция multiply () была вызвана с одним аргументом. В таком случае давайте вернем функцию doMultiply (), которая при последующем вызове выполняет фактическое умножение.

doMultiply () — это замыкание, потому что оно захватывает переменную number1 из области видимости multiply ().

Заключение

Сравните свои ответы с ответами в статье:

  • Вы хорошо понимаете замыкание, если правильно ответили на 5 или более вопросов.
  • Но если вы правильно ответили менее чем на 5 вопросов, вам нужно освежить знание о замыкание. Рекомендую почитать мой пост: A Simple Explanation of JavaScript Closures.