Это ключевое слово

Ключевое слово 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 объект