Ответ
В JavaScript значение this определяется тем, как вызывается функция, а не тем, где она объявлена. Изменить его можно явно несколькими способами.
1. Явный вызов с помощью call(), apply() и bind():
Эти методы доступны у всех функций.
-
func.call(thisArg, arg1, arg2, ...)Вызывает функцию с заданным контекстомthisArgи аргументами, переданными индивидуально.function greet(greeting, punctuation) { console.log(`${greeting}, ${this.name}${punctuation}`); } const person = { name: 'Alice' }; greet.call(person, 'Hello', '!'); // Вывод: Hello, Alice! -
func.apply(thisArg, [argsArray])Аналогиченcall(), но аргументы передаются в виде массива (или array-like объекта).const args = ['Hi', '?']; greet.apply(person, args); // Вывод: Hi, Alice?Полезно, когда количество аргументов неизвестно заранее.
-
func.bind(thisArg, arg1, arg2, ...)Создает новую функцию, которая при вызове будет иметь заданный контекстthis. Аргументы, переданные вbind, будут подставлены первыми.const boundGreet = greet.bind(person, 'Hey'); boundGreet('...'); // Вывод: Hey, Alice... // Контекст person зафиксированbind()часто используется для фиксации контекста в колбэках (например, в обработчиках событий).
2. Особенности стрелочных функций:
Стрелочные функции не имеют своего this. Они лексически захватывают значение this из окружающей их области видимости. Методы call(), apply(), bind() не работают для изменения их контекста.
const obj = {
value: 'My Value',
regularFunc: function() {
console.log(this.value); // 'My Value' (this = obj)
},
arrowFunc: () => {
console.log(this.value); // undefined (this берется из внешней области, например, global)
}
};
const newContext = { value: 'New Value' };
obj.regularFunc.call(newContext); // 'New Value' (контекст изменен)
obj.arrowFunc.call(newContext); // undefined (контекст НЕ изменен)
3. Ключевое слово new:
При вызове функции с оператором new создается новый объект, и this внутри этой функции-конструктора ссылается на этот новый объект.
function Car(model) {
this.model = model; // this указывает на новый экземпляр
}
const myCar = new Car('Tesla');
console.log(myCar.model); // 'Tesla'
Итог: Для явного управления контекстом используйте call/apply для немедленного вызова или bind для создания новой функции с фиксированным контекстом. Выбирайте обычные функции, когда нужен динамический this, и стрелочные — когда нужно сохранить контекст родительской функции.
Ответ 18+ 🔞
Давай разберем эту тему про this, а то у многих мозг набекрень встаёт, как только речь заходит о контексте. Ситуация, блядь, пиздопроебибна, но на самом деле всё логично, если понять принцип.
Смотри, главная мысль, которую надо вбить себе в башку: this в JavaScript определяется не тем, где функция написана, а тем, как её вызвали. Вот это — ключ ко всему. А если хочешь этот контекст подкрутить под себя, есть несколько легальных способов, прям как в хорошем автосервисе.
1. Прямой приказ: call(), apply() и bind()
Эти три товарища — твои лучшие друзья, они прямо в прототипе у каждой функции висят.
-
func.call(thisArg, arg1, arg2, ...)Ты прямо командуешь: «Функция, вызывайся вот в этом контексте (thisArg), и вот тебе аргументы по одному». Просто и ясно.function greet(greeting, punctuation) { console.log(`${greeting}, ${this.name}${punctuation}`); } const person = { name: 'Alice' }; greet.call(person, 'Hello', '!'); // Вывод: Hello, Alice!Всё,
thisвнутриgreetтеперь — это наш объектperson. Никаких неожиданностей. -
func.apply(thisArg, [argsArray])Брат-близнецcall, но для тех, кто любит работать с массивами. Аргументы ты суёшь не поштучно, а пачкой, в одном массиве.const args = ['Hi', '?']; greet.apply(person, args); // Вывод: Hi, Alice?Охуенно удобно, когда заранее не знаешь, сколько аргументов на тебя свалится.
-
func.bind(thisArg, arg1, arg2, ...)А вот это, чувак, не вызов, а создание новой сущности.bindне вызывает функцию сразу. Он возвращает тебе новую функцию, у которой намертво, намертво приклеен нужный контекстthisArg. Как кандалы.const boundGreet = greet.bind(person, 'Hey'); boundGreet('...'); // Вывод: Hey, Alice... // Контекст person теперь зафиксирован навеки. Можно спать спокойно.Идеально для колбэков, особенно в обработчиках событий, где
thisимеет привычку убегать, как последняя хитрая жопа.
2. Стрелочные функции — особая статья, ёпта
Вот тут внимание, блядь. У стрелочных функций своего this НЕТ ВООБЩЕ. Вообще. Ноль. Они берут его снаружи, из той области, где были объявлены. И самое главное — методы call(), apply(), bind() на них не действуют. Они просто игнорируются. Представь, что ты кричишь на стену.
const obj = {
value: 'My Value',
regularFunc: function() {
console.log(this.value); // 'My Value' (this = obj, всё ок)
},
arrowFunc: () => {
console.log(this.value); // undefined (this взялся снаружи, например, из global)
}
};
const newContext = { value: 'New Value' };
obj.regularFunc.call(newContext); // 'New Value' (контекст поменяли)
obj.arrowFunc.call(newContext); // undefined (контекст НЕ поменяли, похуй на call)
Запомни: стрелочные — для фиксации контекста родителя, обычные — когда тебе нужен динамический this.
3. Магия слова new
Когда вызываешь функцию через new, происходит ёперный театр: создаётся новый пустой объект, и this внутри конструктора начинает указывать именно на него.
function Car(model) {
this.model = model; // this теперь привязан к новенькому экземпляру
}
const myCar = new Car('Tesla');
console.log(myCar.model); // 'Tesla'
Вот и вся магия. Никаких духов, только строгие правила языка.
Итог, блядь:
Хочешь рулить контекстом в лоб — бери call или apply. Нужно привязать контекст раз и навсегда, чтобы потом не бздеть — твой выбор bind. Выбирай обычные функции, если this должен прыгать, и стрелочные, если нужно, чтобы он сидел на месте, как приклеенный. Главное — понять, кто здесь главный, и не охуеть от неожиданностей.