Перейти к содержанию

Как работает this

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

1. Глобальная область видимости

this

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

2. Вызов функции

foo()

Тут this также ссылается на глобальный объект.

ES5 Замечание: В strict-режиме теряется понятие глобальности, поэтому в этом случае this будет иметь значение undefined.

3. Вызов метода

test.foo()

В данном примере this ссылается на test.

4. Вызов конструктора

new foo()

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

5. Переопределение this

function foo(a, b, c) {}

var bar = {}
foo.apply(bar, [1, 2, 3]) // массив развернётся в a = 1, b = 2, c = 3
foo.call(bar, 1, 2, 3) // аналогично

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

Исходя из этого, в предыдущем примере (строка с apply) правило #3 вызов метода не будет применено, и this внутри foo будет присвоено bar.

Замечание: this нельзя использовать внутри литералов {} (Object) для ссылки на сам объект. Т.е. если мы напишем var obj = {me: this}, то me не будет ссылаться на obj, поскольку this присваивается только по одному из пяти описанных правил.

Наиболее распространенные ошибки

Хотя большинство из примеров ниже наполнены глубоким смыслом, первый из них можно считать ещё одним упущением в самом языке, поскольку он вообще не имеет практического применения.

Foo.method = function () {
  function test() {
    // this ссылается на глобальный объект
  }
  test()
}

Распространенным заблуждением будет то, что this внутри test ссылается на Foo, но это не так.

Для того, чтобы получить доступ к Foo внутри функции test, необходимо создать локальную переменную внутри method, которая и будет ссылаться на Foo.

Foo.method = function () {
  var that = this
  function test() {
    // Здесь используем that вместо this
  }
  test()
}

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

Замечание от перев. Кроме that также часто встречаются this_, self_ и другие варианты, но лучше принять для себя that как стандарт и тогда, возможно, все вокруг тоже будут им пользоваться.

Назначение методов

Еще одной фичей, которая не работает в JavaScript, является создание псевдонимов для методов, т.е. присвоение метода объекта переменной.

var test = someObject.methodTest
test()

Следуя первому правилу test вызывается как обычная функция; следовательно this внутри него больше не ссылается на someObject.

Хотя позднее связывание this на первый взгляд может показаться плохой идеей, но на самом деле именно благодаря этому работает наследование прототипов.

function Foo() {}
Foo.prototype.method = function () {}

function Bar() {}
Bar.prototype = Foo.prototype

new Bar().method()

В момент, когда будет вызван method нового экземпляра Bar, this будет ссылаться на этот самый экземпляр.