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

Почему this присваивается именно так?

важность: 3

Вызовы (1) и (2) в примере ниже работают не так, как (3) и (4):

"use strict"

var obj, method;

obj = {
  go: function() { alert(this); }
};

obj.go();            // (1) object

(obj.go)();          // (2) object

(method = obj.go)();      // (3) undefined

(obj.go || obj.stop)(); // (4) undefined

В чём дело? Объясните логику работы this.

  1. Обычный вызов функции в контексте объекта.

  2. То же самое, скобки ни на что не влияют.

  3. Здесь не просто вызов obj.method(), а более сложный вызов вида (выражение).method(). Такой вызов работает, как если бы он был разбит на две строки:

    f = obj.go; // сначала вычислить выражение
    f();             // потом вызвать то, что получилось

    При этом f() выполняется как обычная функция, без передачи this.

  4. Здесь также слева от точки находится выражение, вызов аналогичен двум строкам.

В спецификации это объясняется при помощи специального внутреннего типа Reference Type.

Если подробнее – то obj.go() состоит из двух операций:

  1. Сначала получить свойство obj.go.
  2. Потом вызвать его как функцию.

Но откуда на шаге 2 получить this? Как раз для этого операция получения свойства obj.go возвращает значение особого типа Reference Type, который в дополнение к свойству go содержит информацию об obj. Далее, на втором шаге, вызов его при помощи скобок () правильно устанавливает this.

Любые другие операции, кроме вызова, превращают Reference Type в обычный тип, в данном случае – функцию go (так уж этот тип устроен).

Поэтому получается, что (method = obj.go) присваивает в переменную method функцию go, уже без всякой информации об объекте obj.

Аналогичная ситуация и в случае (4): оператор ИЛИ || делает из Reference Type обычную функцию.