Практика: контекст функций

// Что будет выведено в консоли и почему? const side = 20; const square = { side: 5, area() { return this.side * this.side; }, perimeter: () => 4 * this.side, }; console.log(square.area()); // ? console.log(square.perimeter()); // ? const area = square.area; console.log(area()); // ? const area2 = square.area.bind({ side: 4 }).bind({ side: 7 }); console.log(area2()); // ?
Ответ
// Что будет выведено в консоли и почему? const side = 20; const square = { side: 5, area() { return this.side * this.side; }, perimeter: () => 4 * this.side, }; console.log(square.area()); // 25 console.log(square.perimeter()); // NaN const area = square.area; console.log(area()); // NaN const area2 = square.area.bind({ side: 4 }).bind({ side: 7 }); console.log(area2()); // 16
 
🎯 Зачем спрашивают
  • Проверить понимание механизма контекста (this) в JavaScript и способность объяснить его на уровне исполнения кода.
  • Убедиться, что кандидат различает типы функций и осознаёт их влияние на контекст:
    • function (создаёт свой this при вызове);
    • arrow function (замыкает this из внешней области).
  • Проверить знание типичных ловушек: потеря контекста при деструктуризации или передаче метода как callback.
  • Понять, насколько глубоко кандидат понимает работу bind, call, apply и их отличия.
 
📝 Ответ
Прежде, чем бросаться решать задачу, внимательно прочитайте весь код. Часто в подобных задачах кандидаты косячат из-за невнимательности. Цель данной задачи проверить понимание работы контекста (this) и его особенностей.
 
При чтении кода обращайте внимание на:
  • тип используемых переменных (var, let, const)
  • если используется var, есть ли “use strict” режим
  • тип функции (arrow, function declaration)
 
Пойдем по порядку.
const side = 20; const square = { side: 5, area() { return this.side * this.side; }, perimeter: () => 4 * this.side, }; // #1 console.log(square.area()); // 25 // #2 console.log(square.perimeter()); // NaN
В первом случае вызывается метод у объекта, объявленный через сокращённый синтаксис объекта (аналог function expression). Поэтому this будет ссылать на объект до точки. А значит, this.side будет равен 5. 5*5 = 25.
 
Во втором случае будет вызван метод объекта, объявленный как стрелочная функция. Стрелочные функции не имеют своего контекста, this будет ссылать на внешний контекст. В данном случае — это контекст всего скрипта, то есть window. В window нет переменной с идентификатором side, поэтому this.side будет равен undefined. Любая математическая операция, где хотя бы один операнд не является числом, будет выдавать NaN (not a number).
 
💡
this определяется способом вызова функции, а не местом объявления.
 
const side = 20; const square = { side: 5, area() { return this.side * this.side; }, perimeter: () => 4 * this.side, }; // #3 const area = square.area; console.log(area()); // NaN // #4 const area2 = square.area.bind({ side: 4 }).bind({ side: 7 }); console.log(area2()); // 16
В третьем случае идет присвоение метода в переменную. Это ведет к потере контекста. Из-за чего this будет ссылать на window.
 
💡
Потеря контекста происходит, потому что при присвоении square.areaarea теряется связь “кто вызвал функцию”.
 
undefined * undefined даст NaN.
 
В четвертом случае метод функции bind переопределяет исходный контекст. Данный метод как раз и нужен для борьбы с потерей контекста. Важно помнить, что переопределине срабатывает единожды, повторные перепривязки не сработают. Потому что bind возвращает новую функцию, у которой контекст уже «жёстко зафиксирован».
Поэтому 4 * 4 = 16.
 
⚖️ Компромиссы
 
🔎 Встречные вопросы
  • Что делает .call() и .apply() по сравнению с bind()?
  • Как можно сохранить контекст без bind()?
  • Как работает this в классах и при наследовании?
  • В чем особенность стрелочных функция?
  • Что такое “use strict”? Как он работает?
 
🚩 Красные флаги
  • Уверенное утверждение, что this в стрелочной функции = window.
  • Попытка решить задачу без анализа, «на автомате».
  • Не упоминание строгого режима.
 
🛠 Практика
Задача 1
"use strict"; function a () { console.log(this); } function b () { a(); } b();
Задача 2
"use strict"; function a () { console.log(this); } function b () { a(); } const c = { a, b, } c.a(); c.b();
Задача 3
"use strict"; const a = () => { console.log(this); }; const c = { a, b: () => { console.log(this); }, }; c.a(); c.b();
 
📚 Источники / ссылки
  • iliakaniliakanПривязка контекста к функции