Ключевое слово this
Одна и та же функция ярлыка может сказать имя кружки, потом потерять объект, потом показать имя чашки. Фигурные скобки на месте. Изменился вызов. JavaScript выбирает this в момент вызова, а не пока вы набираете функцию.
После простого вызова метода
Страница методов положила функцию на объект и запустила её как product.tag(). В той форме this был объектом перед точкой. На этом страница остановилась. Здесь функция остаётся, а вызов меняется: снят с объекта, наведён через call, зафиксирован через bind или записан стрелкой.
Пять форм, которыми вызов задаёт this
📊 Метод, голый, call, bind, стрелка
| Форма | Пример | Куда садится this |
|---|---|---|
| метод | product.tag() |
объект перед точкой |
| голый | let show = product.tag; show() |
не тот объект (undefined в строгом режиме) |
| call | product.tag.call(cup) |
объект, который вы отдаёте call, только на этот запуск |
| bind | product.tag.bind(product) |
зафиксирован на том объекте для следующих вызовов |
| стрелка | () => this.name внутри другой функции |
this внешней функции, не объект перед точкой |
Назовите вызов, прежде чем читать this. Положить функцию на объект не замораживает this. Решает вызов. bind решает заранее для позднего вызова. Стрелка игнорирует вызов и смотрит на функцию, которая её окружает.
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
console.log(product.tag());
Точка по-прежнему называет объект
product.tag() запускает tag и ставит this на product. Консоль печатает Mug. Это правило со страницы методов, оставленное здесь базовой линией. Следующие четыре вызова специально сходят с этой линии.
"use strict";
let product = {
name: "Mug",
tag() {
if (this == null) {
return "missing";
}
return this.name;
}
};
let show = product.tag;
console.log(show());
Снимите функцию с объекта — кружка уходит вместе с точкой
show и product.tag — одна функция. У show() нет объекта перед точкой, поэтому в строгом режиме this равен undefined. Сторож возвращает missing. Уберите сторожа — this.name бросит ошибку. На этой странице строгий режим, чтобы результат был предсказуем. Нестрогий скрипт может направить голый вызов на глобальный объект.
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
let cup = { name: "Cup" };
console.log(product.tag.call(cup));
call одалживает функцию одному объекту
product.tag.call(cup) по-прежнему выполняет tag кружки, но на этот запуск this — это cup. Консоль печатает Cup. product.name остаётся Mug. call не приклеивает функцию к cup. apply делает ту же работу, когда лишние аргументы лежат в массиве — этому ярлыку они не нужны.
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
let show = product.tag.bind(product);
console.log(show());
bind сохраняет объект для позднего голого вызова
bind возвращает новую функцию. Внутри неё this остаётся product, хотя у show() нет точки. Консоль печатает Mug. Исходный tag не меняется. Берите bind, когда кнопка, таймер или другая функция вызовет метод без объекта впереди.
"use strict";
let shelf = {
name: "Shelf",
make() {
let product = {
name: "Mug",
tag: () => this.name
};
return product.tag();
}
};
console.log(shelf.make());
Стрелка не берёт this у точки
product.tag() похож на вызов метода, но tag — стрелка. У стрелки нет своего this. Она берёт this из make, а make шёл как shelf.make(), значит this — это shelf. Консоль печатает Shelf, не Mug. Обычный метод на product напечатал бы Mug. Стрелки были на более ранней странице; здесь только их действие на this.
Подгоните вызов под задачу
Объект стоит перед точкой? Читайте this как этот объект. Сняли функцию и не зафиксировали? Не ждите объект. Другой объект, один запуск? Используйте call. Поздний вызов без точки всё ещё должен видеть кружку? Сначала bind. Написали стрелку? Смотрите наружу, на окружающую функцию, а не на объект перед точкой. Конструктор и класс тоже задают this, им отведена более поздняя страница. Дальше JSON: текст, который описывает данные, а не новое правило для this.
Положите зафиксированный ярлык на страницу
Зафиксируйте tag на кружке через bind, затем вызовите новую функцию без точки. Запишите результат в абзац.
<!DOCTYPE html>
<html>
<head>
<title>this-keyword — page</title>
</head>
<body>
<p id="line">…</p>
<script>
"use strict";
let product = {
name: "Mug",
tag() {
return this.name;
}
};
let show = product.tag.bind(product);
let box = document.getElementById("line");
box.textContent = show();
</script>
</body>
</html>
Абзац показывает Mug. У show() нет объекта перед точкой, и строка всё равно называет кружку, потому что bind зафиксировал this. Поменяйте только product.name, обновите страницу — абзац последует. Следующий урок: JSON в JavaScript — текст, который описывает данные, а не новое правило для this.
Шаги практики
- Вызовите
product.tag()и прочитайтеMug. - Скопируйте функцию в
show, вызовитеshow()в строгом режиме и прочитайтеmissing. - Вызовите
product.tag.call(cup)и прочитайтеCup. - Зафиксируйте
tagнаproduct, вызовите новую функцию без точки и прочитайтеMug. - Запустите
shelf.make()и прочитайтеShelf, неMug. - В HTML-демо поменяйте только
product.name, обновите и прочитайте абзац.
Частые промахи
- Считать
thisзамороженным только потому, что функция лежит на объекте - Вызывать
show()в строгом режиме и всё ещё ждатьMug - Думать, что
callкопируетtagнаcup - Ждать, что
bindперепишет исходныйtag, а не вернёт новую функцию - Писать стрелку вместо метода и ждать объект перед точкой
- Читать следующую страницу как ещё одно правило
this— JSON это текстовый формат данных
Кратко
thisвыбирает вызов, не скобкиobject.method()ставитthisна объект перед точкой- Голый вызов в строгом режиме не направляет
thisна тот объект callставитthisна переданный объект, только на этот запускbindвозвращает функцию, у которойthisостаётся зафиксирован- Стрелка берёт
thisиз окружающей функции - Зафиксированный вызов может заполнить одну строку страницы
- Дальше: JSON, текст, который описывает данные
🧠 Проверьте Свои Знания
Проверьте Свои Знания
Бросьте себе вызов с помощью этой интерактивной викторины и узнайте, насколько хорошо вы понимаете тему
📝 Инструкции
- Внимательно прочитайте каждый вопрос
- Выберите лучший ответ на каждый вопрос
- Вы можете пересдавать тест столько раз, сколько захотите
- Ваш прогресс будет показан вверху