this
Подумайте о слове «я». В устах Анны оно означает Анну, в устах Боба — Боба. Само слово не помнит, кто его написал: его смысл решает тот, кто говорит сейчас.
Слово this в методе работает так же. Как вы уже знаете, метод, вызванный через точку, получает в this объект перед точкой. Но тот же метод, сохранённый в константе, свой объект теряет:
"use strict";
const user = {
name: "Ann",
greet() {
return `Hi, ${this.name}`;
}
};
console.log(user.greet()); // Hi, Ann
const greet = user.greet;
console.log(greet()); // ✗TypeError: Cannot read properties of undefined (reading 'name')Это текст Node.js и Chrome; в Firefox и Safari сообщение звучит иначе. Первый вызов печатает Hi, Ann, второй останавливает программу.
this решает вызов
this определяется в момент вызова, а не там, где написана функция. Это частый вопрос на собеседовании: «Чему равен this?» Для обычной функции ответ начинается со слов «смотря как вызвали». Разберём три вызова.
Вызов через точку
В вызове user.greet() перед точкой стоит user, поэтому this равен user. «Я» говорит user, и this.name читает его имя.
Вызов без точки
Константа greet хранит ту же функцию, но вызов greet() идёт без точки, и объекта у него нет. Что попадёт в this, зависит от режима:
- в строгом режиме
thisравенundefined, а чтениеundefined.nameостанавливает программу сTypeError; - без
"use strict"вthisпопадает глобальный объект — встроенный объект, общий для всей программы.
Во втором случае ошибки нет, но имени пользователя функция всё равно не видит.
Метод как колбэк
Метод теряет объект и тогда, когда сам метод передают колбэком. Вызов ["Bob"].forEach(user.greet) передаёт forEach только функцию, и forEach вызывает её без точки. Это как переслать чужое сообщение «я приду» без подписи: кто это «я», уже не понять.
Метод bind
У каждой функции есть метод bind. Вызов user.greet.bind(user) не выполняет функцию, а возвращает новую, у которой this всегда равен user, как бы её ни вызвали:
"use strict";
const user = {
name: "Ann",
greet() {
return `Hi, ${this.name}`;
}
};
const greet = user.greet.bind(user);
console.log(greet()); // Hi, Ann
console.log(["Bob", "Eve"].map(greet).join(" ")); // Hi, Ann Hi, AnnРазберём по шагам:
user.greet.bind(user)возвращает новую функцию, к которой навсегда привязанuser.greet()вызывается без точки, но печатаетHi, Ann.mapполучаетgreetколбэком и вызывает её для каждого элемента без точки.thisкаждый раз равенuser, поэтому оба результата —Hi, Ann.
Стрелочная функция и this
У стрелочной функции нет своего this. Она берёт this из кода вокруг, из того места, где она написана. Своего «я» у неё нет: она говорит от имени того кода, внутри которого её написали. Поэтому она хорошо подходит как колбэк внутри метода:
"use strict";
const team = {
name: "Red",
members: ["Ann", "Bob"],
labels() {
return this.members.map((m) => `${m}-${this.name}`);
}
};
console.log(team.labels().join(" ")); // Ann-Red Bob-RedСтрелочная функция написана внутри метода labels, поэтому её this — это this метода, то есть team. Обычную функцию function (m) { … } на этом месте map вызвал бы без точки, и this в ней был бы undefined.
Здесь аналогия со словом «я» перестаёт работать: человек не может говорить чужим «я», а стрелочная функция только так и делает.
Частая ошибка
Метод в литерале объекта — так называют фигурные скобки { … } с ключами и значениями — сделали стрелочной функцией:
const box = {
size: 3,
getSize: () => this.size // ✗
};
console.log(box.getSize()); // undefinedОшибки нет, но вместо 3 программа печатает undefined. Стрелочная функция берёт this из кода вокруг литерала, а не из объекта box. На верхнем уровне файла в Node.js this — пустой объект, поэтому this.size даёт undefined, а не ошибку. Вызов через точку этого не меняет. Если методу нужен свой объект, пишите его обычной функцией, например в короткой форме: getSize() { return this.size; }.
Главное
thisрешает вызов: через точку это объект перед точкой, без точки в строгом режиме —undefined.- Метод, сохранённый в переменной или переданный колбэком, теряет объект;
bindвозвращает функцию с навсегда привязаннымthis. - У стрелочной функции нет своего
this: она берёт его из кода вокруг, поэтому подходит как колбэк в методе, но не как сам метод.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.