this

Поведение ключевого слова this в JavaScript несколько отличается по сравнению с остальными языками. Имеются также различия при использовании this в строгом и нестрогом режиме.

В большинстве случаев значение this определяется тем, каким образом вызвана функция. Значение this не может быть установлено путем присваивания во время исполнения кода и может иметь разное значение при каждом вызове функции. В ES5 представлен метод bind(), который используется для привязки значения ключевого слова this независимо от того, как вызвана функция. Также в ES2015 представлены стрелочные функции, которые не создают собственные привязки к this (они сохраняют значение this лексического окружения, в котором были созданы).

Синтаксис

this

Значение

Свойство контекста выполнения кода (global, function или eval), которое в нестрогом режиме всегда является ссылкой на объект, а в строгом режиме может иметь любое значение.

Global контекст

В глобальном контексте выполнения (за пределами каких-либо функций) this ссылается на глобальный объект вне зависимости от режима (строгий или нестрогий).

// В браузерах, объект window также является объектом global:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"

Note: Вы всегда можете легко получить объект global, используя глобальное свойство globalThis, независимо от текущего контекста, в котором выполняется ваш код.

Function контекст

В пределах функции значение this зависит от того, каким образом вызвана функция.

Простой вызов

Поскольку следующий код не в строгом режиме, и значение this не устанавливается вызовом, по умолчанию будет использоваться объект global, которым в браузере является window.

function f1(){
  return this;
}

// В браузере:
f1() === window; // window - глобальный объект в браузере

// В Node:
f1() === global; // global - глобальный объект в Node

В строгом режиме, если значение this не установлено в контексте выполнения, оно остается undefined, как показано в следующем примере:

function f2(){
  "use strict"; // см. strict mode
  return this;
}

f2() === undefined; // true
Во втором примере this должно иметь значение undefined, потому что функция f2 была вызвана напрямую, а не как метод или свойство объекта (например, window.f2()). Реализация этой особенности не поддерживалась в некоторых браузерах, когда они впервые начали поддерживать строгий режим. В результате они некорректно возвращали объект window.

Для того, чтобы при вызове функции установить this в определенное значение, используйте call() или apply(), как в следующих примерах.

Пример 1

// В качестве первого аргумента методов call или apply может быть передан объект, 
// на который будет указывать this.
var obj = {a: 'Custom'};

// Это свойство принадлежит глобальному объекту
var a = 'Global';

function whatsThis() {
  return this.a;  //значение this зависит от контекста вызова функции

}

whatsThis();          // 'Global'
whatsThis.call(obj);  // 'Custom'
whatsThis.apply(obj); // 'Custom'

Пример 2

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// Первый параметр - это объект для использования в качестве 
// 'this', последующие параметры передаются как 
// аргументы функции call
add.call(o, 5, 7); // 16

// Первый параметр - это объект для использования в качестве
// 'this', второй - массив, чьи члены используются
// в качестве аргументов функции call
add.apply(o, [10, 20]); // 34

Обратите внимание, что в нестрогом режиме, если значение, переданное в call или apply как this, не является объектом, будет сделана попытка преобразовать его в объект с помощью внутренней операции ToObject. Таким образом, если переданное значение является примитивом, таким как 7 или 'foo', оно будет преобразовано в Object с использованием связанного конструктора, так что примитивное число 7 будет преобразовано в объект так, как будто с помощью new Number(7), а строка 'foo' - как будто с помощью new String('foo'), например

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7);     // [object Number]
bar.call('foo'); // [object String]

Метод bind

ECMAScript 5 представил Function.prototype.bind(). Вызов f.bind(someObject) создает новую функцию с тем же телом и областью действия, что и f, но там, где в исходной функции используется this, в новой функции оно постоянно будет связано с первым аргументом bind, независимо от того, как функция используется.

function f() {
  return this.a;
}

var g = f.bind({a: 'azerty'});
console.log(g()); // azerty

var h = g.bind({a: 'yoo'}); // bind only works once!
console.log(h()); // azerty

var o = {a: 37, f: f, g: g, h: h};
console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty

Стрелочные функции

В стрелочных функциях, this привязан к окружению, в котором была создана функция. В глобальной области видимости this будет указывать на глобальный объект.

var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

Note: если аргумент this передаётся в call, bind или apply при вызове стрелочной функции, он будет проигнорирован. Вы всё ещё можете добавить аргументы к вызову, но первый аргумент (thisArg) должен быть установлен в null.

Неважно, как стрелочная функция foo() будет вызвана, её значение this будет указывать на глобальный объект. this будет сохранять свое значение, даже если функция foo() будет вызвана как метод объекта (что в обычных функциях связывает this с объектом вызова) или с использованием методов call, apply или bind:

// Вызов функции как метода объекта
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// Попытка установить this с помощью call
console.log(foo.call(obj) === globalObject); // true

// Попытка установить this с помощью bind
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

Несмотря ни на что, this стрелочной функции foo() имеет то же значение, что и при создании функции (глобальный объект в примере выше). То же самое касается стрелочных функций, созданных внутри других функций: их this будет привязан к окружению.

// Создаем объект obj, содержащий метод bar, который возвращает функцию,
// которая возвращает свой this. Возвращаемая функция создана
// как стрелочная функция, таким образом её this постоянно замкнут 
// на this функции, в которой она создана. Значение bar может быть установлено 
// в вызове, который, в свою очередь, устанавливает значение возвращаемой функции.
var obj = { bar : function() {
                    var x = (() => this);
                    return x;
                  }
          };

// Вызываем bar как метод объекта obj, устанавливая его this на obj
// Присваиваем ссылку возвращаемой функции переменной fn
var fn = obj.bar();

// Вызываем fn без установки this, что в обычных функциях указывало бы
// на глобальный объект или undefined в строгом режиме.
console.log(fn() === obj); // true

// Но будьте осторожны, если вы ссылаетесь на метод obj, не вызывая его
var fn2 = obj.bar;
// Вызов this стрелочной функции изнутри метода bar вернёт теперь window,
// потому что он следует за this из fn2.
console.log(fn2()() == window); // true

В примере выше, функция (назовем её анонимной функцией A), присвоенная методу obj.bar, возвращает другую функцию (назовем её анонимной функцией B) которая создана как стрелочная функция. В результате, this функции B при вызове замкнут на this, принадлежащий obj.bar (функции A). this функции B всегда будет иметь то значение, которое он получил при создании. В примере выше, this функции B указывает на this функции A,которым является obj, таким образом this будет равен obj даже тогда, когда будет вызван методом, который в нормальных условиях устанавливал бы значение this равным undefined или глобальному обьекту (или любым другим методом, как в предыдущем примере в глобальном контексте выполнения).

В методе объекта

Когда функция вызывается как метод объекта, используемое в этой функции ключевое слово this принимает значение объекта, по отношению к которому вызван метод.

В следующем примере, когда вызвано свойство o.f() , внутри функции this привязано к объекту o.

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // logs 37

Необходимо отметить, что на поведение this совсем не влияет то, как или где была определена функция. В предыдущем примере мы определили функцию внутри свойства f во время определения объекта o. Однако, мы могли бы также просто определить сначала функцию, а затем закрепить ее за за свойством o.f. В этом случае поведение this не изменится:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

Эти примеры показывают, что имеет значение только то, что функция была вызвана из свойства f объекта o.

Аналогично, привязывание this обуславливается наличием ближайшей ссылки на объект или свойство. В следующем примере, когда мы вызываем функцию, мы обращаемся к ней как к методу g объекта o.b. На этот раз во время выполнения, this, что находится внутри функции, будет ссылаться на o.b. Тот факт, что объект является членом объекта o, не имеет значения; важна только ближайшая ссылка.

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42

this в цепочке object's prototype

Это же представление справедливо и для методов, определенных где-либо в цепочке object's prototype. Если метод находится в цепочке прототипов, то this ссылается на объект, на котором был вызван метод, т.е. так, словно метод является методом самого объекта, а не прототипа.

var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

В этом примере объект, которому присвоена переменная p, не имеет собственного свойства f, а наследует это свойство от своего прототипа. Однако, совершенно неважно, что поиск свойства f в конце концов обнаружит его на объекте o. Поскольку поиск начался с p.f, то и свойство this внутри функции f будет ссылаться на объект p. Таким образом, если f вызывается как метод p, то и this относится к p. Это полезная особенность прототипного наследования JS.

this с геттерами/сеттерами

Все те же утверждения справедливы, если функция вызывается из геттера или сеттера. Для функции, которая используется как геттер или сеттер this привязан к объекту, свойство которого необходимо извлечь через геттер/сеттер.

function modulus(){
  return Math.sqrt(this.re * this.re + this.im * this.im);
}

var o = {
  re: 1,
  im: -1,
  get phase(){
    return Math.atan2(this.im, this.re);
  }
};

Object.defineProperty(o, 'modulus', {
    get: modulus, enumerable:true, configurable:true});

console.log(o.phase, o.modulus); // logs -0.78 1.4142

В конструкторе

Когда функция используется как конструктор (с ключевым словом new ), this связано с создаваемым новым объектом.

Примечание: по умолчанию конструктор возвращает объект, на который ссылается this, но он может вернуть и другой объект (если возвращаемое значение не является объектом, тогда будет возвращен объект с this).

/*
 * Конструктор работает таким образом:
 *
 * function MyConstructor(){
 *   // фактический код, составляющий тело функции.
 *   // создание свойств с |this| по 
 *   // желанию, определяя их значения; например,
 *   this.fum = "nom";
 *   // и т.д.
 *
 *   // Если функция возвращает выражение,
 *   // возвращающее объект, этот объект будет 
 *   // результатом выражения |new|. В обратном случае,
 *   // результат выражения - объект,
 *   // в данный момент привязанный к |this|
 *   // (т.е. наиболее часто встречающийся случай).
 * }
 */

function C() {
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2() {
  this.a = 37;
  return {a: 38};
}

o = new C2();
console.log(o.a); // logs 38

В последнем примере (C2), из-за того, что конструктор вернул объект, новый объект, к которому было привязано this, был просто отброшен. (Это фактически делает выражение "this.a = 37;" "мертвым" кодом. Он не является буквально нерабочим, так как он выполняется, но он может быть изъят без каких-либо внешних эффектов.)

call и apply

Когда в теле функции используется ключевое слово this, его значение может быть привязано к конкретному объекту в вызове при помощи методов call или apply, которые наследуются всеми функциями от Function.prototype.

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// Первый параметр - это объект, который следует использовать как
// 'this', последующие параметры передаются 
// как аргументы при вызове функции
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16

// Первый параметр - объект, который следует использовать как
// 'this', второй параметр - массив, 
// элементы которого используются как аргументы при вызове функции
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34

Необходимо отметить, что если методам call и apply передается значение с this, которое не является при этом объектом, будет предпринята попытка конвертировать значение в объект, используя внутреннюю операцию ToObject. Если переданное значение является примитивным типом, например 7 или 'foo', оно будет преобразовано в объект с использованием родственного конструктора, так примитив 7 преобразовывается в объект через new Number(7), а строка 'foo' в объект через new String('foo'), и т.д.

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7); // [object Number]

Как обработчик событий DOM

Когда функция используется как обработчик событий, this присваивается элементу с которого начинается событие (некоторые браузеры не следуют этому соглашению для слушателей, добавленных динамически с помощью всех методов, кроме addEventListener).

// Когда вызывается как слушатель, связанный элемент становится синим
function bluify(e) {
  // Всегда true
  console.log(this === e.currentTarget); 
  // true, когда currentTarget и target один объект
  console.log(this === e.target);
  this.style.backgroundColor = '#A5D9F3';
}

// Получить список каждого элемента в документе
var elements = document.getElementsByTagName('*');

// Добавить bluify как слушателя кликов, чтобы при
// нажатии на элемент он становился синим
for (var i = 0; i < elements.length; i++) {
  elements[i].addEventListener('click', bluify, false);
}

В инлайновом обработчике событий

Когда код вызван из инлайнового обработчика, this указывает на DOM элемент, в котором расположен код события:

<button onclick="alert(this.tagName.toLowerCase());">
  Показать this
</button>

Код выше выведет 'button'. Следует отметить, что this будет указывать на DOM элемент только во внешних (не вложенных) функциях:

<button onclick="alert((function() {return this;} ()));">
  Показать вложенный this
</button>

В этом случае this вложенной функции не будет установлен, так что будет возвращен global/window объект.

Спецификации

Specification
ECMAScript (ECMA-262)
Определение 'The this keyword' в этой спецификации.

Совместимость

Update compatibility data on GitHub
КомпьютерыМобильныеServer
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome для AndroidFirefox для AndroidOpera для AndroidSafari on iOSSamsung InternetNode.js
thisChrome Полная поддержка 1Edge Полная поддержка 12Firefox Полная поддержка 1IE Полная поддержка 4Opera Полная поддержка 9.5Safari Полная поддержка 1WebView Android Полная поддержка 1Chrome Android Полная поддержка 18Firefox Android Полная поддержка 4Opera Android Полная поддержка 10.1Safari iOS Полная поддержка 1Samsung Internet Android Полная поддержка 1.0nodejs Полная поддержка 0.1.100

Легенда

Полная поддержка  
Полная поддержка

Смотри также