Ключевое слово this
относится к текущему контексту выполнения.
По умолчанию this
в функции имеет глобальный контекст, который всегда является объектом окна в браузере:
function foo() {
return this;
}
console.assert(foo() === window);
Однако при вызове в качестве конструктора оператор new
устанавливает this
для объекта, созданного из прототипа функции. Этот контекст уникален для каждого экземпляра.
function foo() {
return this;
}
console.assert(new foo() !== window);
console.assert(new foo() !== new foo());
Если у объекта есть метод, this
в этом методе является этим объектом по умолчанию:
const question = {
ask: function () {
return this;
}
};
console.assert(question.ask() === question);
Теперь вот почему имеет значение текущий контекст выполнения.
Если вы возьмете этот метод за пределы его объекта, тогда контекст этого метода по умолчанию будет иметь глобальный контекст:
const question = {
ask: function () {
return this;
}
};
const ask = question.ask;
console.assert(ask() === window);
Для решения этой проблемы вы можете использовать bind
, call
или apply
:
const question = {
ask: function () {
return this;
}
};
const ask = question.ask;
console.assert(ask.bind(question)() === question);
console.assert(ask.call(question) === question);
console.assert(ask.apply(question) === question);
Вы, наверное, слышали о функциях стрелок, которые связывают this
с контекстом, который был доступен во время определения функции.
Ранее нам приходилось сохранять this
в переменной (обычно называемой that
) для ссылки на правильный контекст. (Или используйте bind
.)
function foo() {
const that = this;
// By the time the function executes, the execution context
// will be different even though we invoked the function
// as a constructor.
setTimeout(function () {
console.assert(that !== this);
console.assert(this === window);
}, 100);
}
new foo();
Эта техника стала устаревшей с функциями стрелок:
function foo() {
setTimeout(() => {
console.assert(this !== window);
}, 100);
}
new foo();
Однако помните, что функции имеют ограниченную лексику, поэтому не даст ожидаемый результат:
const question = {
ask: () => {
return this;
}
};
console.assert(question.ask() === window);
Почему? На момент определения функции стрелки единственным контекстом, доступным в лексической области, был глобальный контекст.