Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Примусове задання this при виклику». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Контекст задають трьома явними методами: `call(thisArg, a, b)` і `apply(thisArg, [a, b])` викликають функцію негайно, а `bind(thisArg)` повертає нову функцію з назавжди прив'язаним `this`.** Крім них контекст встановлюється неявно: виклик через крапку робить `this` самим об'єктом, стрілкові функції беруть `this` із зовнішньої області, `Reflect.apply` це сучасний аналог `apply`, а `new` завжди створює власний об'єкт і перекриває навіть `bind`. ```javascript function greet() { console.log(`Hello, I am ${this.name}`); } const user = { name: 'Maria' }; greet.call(user); // одразу greet.apply(user, []); // одразу, аргументи масивом greet.bind(user)(); // нова функція, виклик пізніше ``` **Ключове:** `call` і `apply` викликають одразу, `bind` прив'язує назавжди, а `new` має пріоритет над усіма ними.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Примусово задати `this` можна методами `call`, `apply` і `bind`, а також через виклик функції як методу об'єкта, стрілкові функції, `Reflect.apply` і оператор `new`.** Різниця між ними в тому, коли відбувається виклик і чи можна змінити контекст згодом. ## Теорія ### TL;DR - `call(thisArg, a, b)` викликає функцію **одразу**, аргументи через кому. - `apply(thisArg, [a, b])` те саме, але аргументи **масивом**. - `bind(thisArg)` **не викликає**, а повертає нову функцію з прив'язаним `this`. - `obj.method()` задає `this = obj` **неявно**. - Стрілкові функції власного `this` не мають і беруть його із зовнішньої області. - `Reflect.apply(fn, thisArg, args)` це сучасний аналог `apply`. - `new Func()` створює новий об'єкт і перекриває навіть прив'язку через `bind`. ### Швидкий приклад ```javascript function greet() { console.log(`Привіт, я ${this.name}`); } const user = { name: 'Maria' }; greet.call(user); // Привіт, я Maria ``` Тут `this` всередині `greet` примусово вказує на `user`. ### call і apply: негайний виклик із заданим контекстом Метод `Function.prototype.call()` викликає функцію **одразу** і дозволяє **вказати `this` вручну**: ```javascript function greet() { console.log(`Привіт, я ${this.name}`); } const user = { name: 'Maria' }; greet.call(user); // Привіт, я Maria ``` Метод `apply()` робить те саме, що й `call`, але приймає **аргументи у вигляді масиву**: ```javascript function introduce(city, job) { console.log(`Я ${this.name} з міста ${city}, працюю як ${job}`); } const user = { name: 'Maria' }; introduce.apply(user, ['Kyiv', 'Frontend-розробник']); // Я Maria з міста Kyiv, працюю як Frontend-розробник ``` ### bind: нова функція з прив'язаним контекстом Метод `bind()` не викликає функцію одразу, а **створює нову**, у якої `this` уже «прив'язаний» назавжди: ```javascript function sayHi() { console.log(`Привіт, я ${this.name}`); } const user = { name: 'Maria' }; const sayHiBound = sayHi.bind(user); sayHiBound(); // Привіт, я Maria ``` Відмінність: - `call` / `apply` **викликають одразу**; - `bind` **створює копію із закріпленим контекстом**. ### Неявний контекст: метод об'єкта і стрілкові функції Якщо викликати функцію **через крапку в об'єкта**, `this` автоматично вказує на цей об'єкт: ```javascript const user = { name: 'Maria', sayHi() { console.log(`Привіт, я ${this.name}`); } }; user.sayHi(); // Привіт, я Maria ``` Це **неявне встановлення `this`**, але по суті те саме. У стрілкових функцій **немає власного `this`**: вони «успадковують» його із зовнішньої області: ```javascript const user = { name: 'Maria', sayHiLater() { setTimeout(() => { console.log(`Привіт, я ${this.name}`); // this = user }, 1000); } }; user.sayHiLater(); // Привіт, я Maria ``` Якби всередині `setTimeout` була звичайна функція, `this` загубився б і став би `window`. ### Reflect.apply, new і навмисна втрата контексту `Reflect.apply()` це сучасний аналог `apply` з ES6: робить те саме, але безпечніше і декларативніше, бо не залежить від того, чи не перевизначили `apply` на самій функції: ```javascript function sayHello() { console.log(`Привіт, ${this.name}`); } const user = { name: 'Maria' }; Reflect.apply(sayHello, user, []); // Привіт, Maria ``` При виклику функції з `new` створюється **новий об'єкт**, і `this` всередині функції вказує на нього, навіть якщо інший `this` прив'язали через `bind`: ```javascript function User(name) { this.name = name; } const Bound = User.bind({ name: 'Maria' }); const u = new Bound('Alice'); console.log(u.name); // Alice, контекст із new перекриває bind ``` Якщо ж треба навпаки «відв'язати» `this` і викликати функцію без контексту, передають `null` або `undefined`: ```javascript function showThis() { console.log(this); } showThis.call(null); // у 'use strict' -> undefined ``` У нестрогому режимі `null` буде підмінено на глобальний об'єкт (`window` або `global`). ### Підсумкова таблиця способів | Спосіб | Викликає одразу | Як задає `this` | Аргументи | | --- | --- | --- | --- | | `call(thisArg, a, b)` | Так | Примусово | Через кому | | `apply(thisArg, [a, b])` | Так | Примусово | Масивом | | `bind(thisArg, a, b)` | Ні | Прив'язує назавжди | Через кому | | `obj.method()` | Так | Неявно (`this = obj`) | Через кому | | `Reflect.apply()` | Так | Примусово (сучасний аналог) | Масивом | | `new Func()` | Так | Новий об'єкт усередині функції | Аргументи конструктора | ### Типові помилки - **Прив'язують `this` до стрілкової функції.** У стрілок немає власного `this`, тому `call`, `apply` і `bind` на нього не впливають, а перший аргумент просто ігнорується. - **Шукають `Reflect.call`.** Такого методу не існує: у `Reflect` є лише `apply`, тому аргументи завжди передають масивом. - **Вважають, що `bind` викличе функцію.** Він лише повертає нову функцію, і без дужок нічого не відбудеться. - **Розраховують на `window` у строгому режимі.** У модулях і класах `this` при `null` залишається `undefined`, тому `this.name` кине помилку. - **Втрачають контекст при передачі методу.** `setTimeout(user.sayHi, 1000)` передає лише функцію без об'єкта; потрібен `user.sayHi.bind(user)` або стрілкова обгортка.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.