24 апреля 2023 г. (изменено: 4 мая 2023 г.)
Канал: @cherkashindev
🧮 Задача на знание this в JavaScript
Иногда на собеседованиях дают подобные каверзные задачи, в которых необходимо хорошо понимать, как работают одновременно: стрелочные функции, контекст this и замыкания. Вот одна из задач, которую мне давали на собеседовании пару лет назад.
Что будет выведено в консоль?
function foo() {
const x = 10;
return {
x: 20,
bar: () => console.log(this.x),
baz() {
console.log(this.x);
},
};
}
foo.x = 50;
const obj1 = foo();
obj1.bar(); // ?
obj1.baz(); // ?
const obj2 = foo.call({ x: 30 });
const x = obj2.bar;
x(); // ?
obj2.bar(); // ?
obj2.baz(); // ?Необходимая теория для решения задачи
this- контекст вызова функции. Если метод вызывается не на объекте, тоthis— глобальный объектwindow, иначеthisуказывает на объект, на котором был вызван метод.- У стрелочной функции нет собственного
this. Если внутри стрелочной функции идёт обращение кthis, его значение, как и обычная переменная, берётся из внешнего лексического окружения. - Если метод объекта присвоить переменной, и вызвать такую переменную-функцию, то контекст потеряется и
thisбудет ссылаться наwindow. Но это не работает в случае стрелочной функции, так как у неё нет собственногоthis, поэтому и потерять она его не может.
Разбор задачи построчно
6. bar — стрелочная функция, this берётся из лексического окружения
7. baz — обычная функция, поэтому this будет ссылаться на возвращаемый объект
15. Так как функция foo вызывается не на объекте, то this в этом случае равен глобальному объекту — window.
16. Так как стрелочная функция берёт this из лексического окружения, то this = window. В консоль будет выведен undefined, потому что на window не определено свойство x.
17. Функция baz реализована с помощью обычной функции, поэтому в данном случае this ссылается на сам объект. В консоль будет выведено 20.
19. Здесь явно указывается контекст вызова функции — объект { x: 30 }
20-21. Так как метод bar реализован с помощью стрелочной функции, то контекст в данном случае не теряется. Используется контекст из лексического окружения — { x: 30 }. В консоль будет выведено 30.
22. Вызывается тот же метод bar, логика точно такая же. В консоль будет выведено 30.
23. Явное указание контекста при вызову функции foo никак не влияет на функцию baz, так как метод вызывается на объекте, и контекстом будет являться данный объект. В консоль будет выведено 20.
**Ответ **⬇️ undefined 20 30 30 20
Теория по теме