Ключевое слово this
относится к значению объекта, который привязан к функции во время ее вызова, а это означает, что его значение различается в зависимости от того, вызывается ли функция как метод, как отдельная функция или как конструктор .
Когда вызывается функция, она создает экземпляр ключевого слова this
за кулисами» как ссылку на объект, содержащий эту функцию, предоставляя доступ к свойствам и методам, определенным рядом с ней, из ее области действия. Работа с this
в некотором смысле аналогична работе с переменной, объявленной с помощью const
. Как и константу, this
нельзя удалить и ее значение нельзя переназначить, но можно изменить методы и свойства объекта, содержащегося в this
ключевом слове.
Глобальная привязка
Вне функции или контекста объекта this
относится к свойству globalThis
, которое в большинстве сред JavaScript является ссылкой на глобальный объект. В контексте сценария, выполняемого в веб-браузере, глобальным объектом является объект window
:
this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}
В Node.js globalThis
— это global
объект:
$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}
Вне строгого режима this
также относится к глобальному объекту внутри отдельной функции, поскольку родительское Window
является объектом, который фактически «владеет» этими функциями.
function myFunction() {
console.log( this );
}
myFunction();
> Window {...}
(function() {
console.log( this );
}());
> Window {...}
При использовании строгого режима внутри отдельной функции this
значение имеет значение undefined
:
(function() {
"use strict";
console.log( this );
}());
> undefined
До введения строгого режима this
null
или undefined
значение заменялось ссылкой на глобальный объект. Иногда вы можете увидеть глобальную привязку, называемую «привязкой по умолчанию» из-за такого устаревшего поведения.
Неявная привязка
Когда функция вызывается как метод объекта, экземпляр this
внутри этого метода ссылается на объект, содержащий этот метод, предоставляя доступ к методам и свойствам, которые находятся рядом с ним:
let myObject = {
myValue: "This is my string.",
myMethod() {
console.log( this.myValue );
}
};
myObject.myMethod();
> "This is my string."
Может показаться, что значение this
зависит от того, как определены функция и включающий ее объект. Вместо этого контекстом значения this
является текущий контекст выполнения . В этом случае контекст выполнения заключается в том, что объект myObject
вызывает метод myMethod
, поэтому значением для this
является myObject
. В контексте предыдущих примеров это может показаться формальностью, но для более продвинутого использования this
необходимо помнить об этом важном различии.
В общем, используйте this
таким образом, чтобы не ожидать, что окружающий код будет иметь какую-либо конкретную структуру. Исключением из этого правила являются стрелочные функции ES5.
this
в стрелочных функциях
В стрелочных функциях this
разрешается привязкой в лексически включающей среде . Это означает, что this
в стрелочной функции относится к значению this
в ближайшем включающем контексте этой функции:
let myObject = {
myMethod() { console.log( this ); },
myArrowFunction: () => console.log( this ),
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
myObject.myArrowFunction();
> Window {...}
В предыдущем примере myObject.myMethod()
регистрирует myObject
как объект, который «владеет» этим методом, но myObject.myArrowFunction()
возвращает globalThis
(или undefined
), поскольку экземпляр this
внутри функции стрелки вместо этого ссылается на самый высокий охватывающий метод. объем.
В следующем примере myEnclosingMethod
при выполнении создает стрелочную функцию для объекта, который ее содержит. Экземпляр this
внутри стрелочной функции теперь ссылается на значение this
внутри окружающей среды, которая является методом, содержащим эту стрелочную функцию. Поскольку значение this
внутри myEnclosingMethod
ссылается на myObject
, после определения функции стрелки this
внутри функции стрелки также относится к myObject
:
let myObject = {
myMethod() { console.log( this ); },
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
Явное связывание
Неявное связывание обрабатывает большинство случаев использования this
. Однако иногда вам может понадобиться значение this
для представления конкретного контекста выполнения, а не предполагаемого контекста. Иллюстративный, хотя и немного устаревший, пример работает с this
внутри функции обратного вызова setTimeout
, поскольку этот обратный вызов имеет уникальный контекст выполнения:
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
myObject.myMethod();
> "This is my string."
setTimeout( myObject.myMethod, 100 );
> undefined
Хотя этот конкретный недостаток setTimeout
с тех пор был устранен с помощью других функций, аналогичные проблемы «потери» this
ранее решались путем создания явной ссылки на значение this
в пределах предполагаемого контекста. Иногда вы можете увидеть случаи, когда this
присваивается переменной с использованием таких идентификаторов, как that
, self
или _this
в устаревших базах кода. Это общие соглашения об идентификаторах для переменных, содержащих переданное this
значение.
Когда вы вызываете функцию с помощью методов call()
, bind()
или apply()
, this
явно ссылается на вызываемый объект:
let myFunction = function() {
console.log( this.myValue );
}
let myObject = {
"myValue" : "This is my string."
};
myFunction.call( myObject );
> "This is my string."
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."
Явная привязка переопределяет значение this
предоставленное неявной привязкой.
let myObject = {
"myValue" : "This string sits alongside myMethod.",
myMethod() {
console.log( this.myValue );
}
};
let myOtherObject = {
"myValue" : "This is a string in another object entirely.",
};
myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."
Если функция вызывается таким образом, что для значения this
будет установлено значение undefined
или null
, это значение заменяется на globalThis
вне строгого режима:
let myFunction = function() {
console.log( this );
}
myFunction.call( null );
> Window {...}
Аналогично, если функция вызывается таким образом, чтобы дать this
примитивное значение, это значение заменяется объектом-оболочкой примитивного значения вне строгого режима:
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> Number { 10 }
В строгом режиме переданное this
значение никоим образом не привязывается к объекту, даже если это примитивное, null
или undefined
значение:
"use strict";
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> 10
myFunction.call( null );
> null
new
переплет
Когда класс используется в качестве конструктора с использованием ключевого слова new
, this
относится к вновь созданному экземпляру:
class MyClass {
myString;
constructor() {
this.myString = "My string.";
}
logThis() {
console.log( this );
}
}
const thisClass = new MyClass();
thisClass.logThis();
> Object { myString: "My string." }
Аналогично, значение this
внутри функции-конструктора, вызываемой с помощью new
относится к создаваемому объекту:
function MyFunction() {
this.myString = "My string.";
this.logThis = function() {
console.log( this );
}
}
const myObject = new MyFunction();
myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }
Привязка обработчика событий
В контексте обработчиков событий значение this
ссылается на объект, который его вызывает. this
означает, что внутри функции обратного вызова обработчика событий ссылается на элемент, связанный с обработчиком:
let button = document.querySelector( "button" );
button.addEventListener( "click", function( event ) { console.log( this ); } );
Когда пользователь взаимодействует с button
в предыдущем фрагменте кода, результатом является объект элемента, содержащий саму кнопку <button>
:
> Button {}
Когда стрелочная функция используется в качестве обратного вызова прослушивателя событий, this
значение снова предоставляется ближайшим включающим контекстом выполнения. На верхнем уровне это означает, this
внутри функции обратного вызова обработчика событий есть globalThis
(или undefined
в строгом режиме):
let button = document.querySelector( "button" );
button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined
Как и в случае с любым другим объектом, когда вы используете методы call()
, bind()
или apply()
для ссылки на функцию обратного вызова прослушивателя событий, this
явно ссылается на объект:
let button = document.querySelector( "button" );
let myObject = {
"myValue" : true
};
function handleClick() {
console.log( this );
}
button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }
Проверьте свое понимание
Для сценария, работающего в веб-браузере, на какой глобальный объект ссылается this
при использовании вне функции или контекста объекта?
window
browser
undefined
объект