Рубрики
Без рубрики

Понимание «Это» в JavaScript

Когда создается функция, создается ключевое слово «Это», которое связано с объектом, в котором работает функция. Многие люди путают с «этим» – понять путаницу.

Автор оригинала: Dario Garcia Moya.

Концептуальный обзор “это”

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

То это Ценность ключевого слова не имеет ничего общего с самой функцией, как функция называется, определяет значение этого

По умолчанию «Это» контекст

// define a function
var myFunction = function () {
  console.log(this);
};

// call it
myFunction();

Что мы можем ожидать это ценность быть? По умолчанию это Должен всегда быть окно объектом, который относится к корне – глобальный объем, за исключением случаев, когда скрипт работает в строгом режиме ( «Использовать строгое» ) это будет неопределенным.

Объектные литералы

var myObject = {
  myMethod: function () {
    console.log(this);
  }
};

Что было бы это контекст здесь? …

  • это?
  • это?
  • Это еще?

Ну, ответ – Мы не знаем Отказ

Помните Значение этого ключевого слова не имеет ничего общего с самой функцией, как функция называется, определяет это значение

Хорошо, давайте немного изменим код …

var myMethod = function () {
  console.log(this);
};

var myObject = {
  myMethod: myMethod
};

Это яснее сейчас? Конечно, все зависит от того, как мы называем функцию.

MyObject В коде сдается свойство под названием MyMethod , какие указывает на MyMethod функция. Когда MyMethod Функция вызывается из глобального охвата, это относится к окну объекта. Когда он называется методом MyObject это относится к MyObject Отказ

myObject.myMethod() // this === myObject
myMethod() // this === window

Это называется неявное обязательство

Явная связывание

Явное привязку – это когда мы явно связываем контекст к функции. Это делается с Звоните () или применять()

var myMethod = function () {
  console.log(this);
};

var myObject = {
  myMethod: myMethod
};

myMethod() // this === window
myMethod.call(myObject, args1, args2, ...) // this === myObject
myMethod.apply(myObject, [array of args]) // this === myObject

Что более прецедент, неявный привязка или явная связка?

var myMethod = function () { 
  console.log(this.a);
};

var obj1 = {
  a: 2,
  myMethod: myMethod
};

var obj2 = {
  a: 3,
  myMethod: myMethod
};

obj1.myMethod(); // 2
obj2.myMethod(); // 3

obj1.myMethod.call( obj2 ); // ?????
obj2.myMethod.call( obj1 ); // ?????

Явное привязку принимает приоритет над неявным связыванием, что означает, что вы должны сначала спросить, если явное привязку применяется перед проверкой неявного привязки.

obj1.myMethod.call( obj2 ); // 3
obj2.myMethod.call( obj1 ); // 2

Твердая связывание

Это делается с Bind () (ES5). Bind () Возвращает новую функцию, которая жестко закодирована, чтобы вызвать оригинальную функцию с это Контекст набор, как вы указали.

myMethod = myMethod.bind(myObject);

myMethod(); // this === myObject

Твердое связывание имеет приоритет над явным связыванием.

var myMethod = function () { 
  console.log(this.a);
};

var obj1 = {
  a: 2
};

var obj2 = {
  a: 3
};

myMethod = myMethod.bind(obj1); // 2
myMethod.call( obj2 ); // 2

Новое обязательство

function foo(a) {
  this.a = a;
}

var bar = new foo( 2 );
console.log( bar.a ); // 2

Итак, это Когда функция была вызвана с новым, относится к созданию нового экземпляра.

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

function foo(something) {
  this.a = something;
}

var obj1 = {};

var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2

var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3

API звонки

Иногда мы используем библиотеку или хелперский объект, который делает что-то (AJAX, обработку событий и т. Д.) И он вызывает пропущенный обратный вызов. Ну, мы должны быть осторожны в этих случаях. Пример:

myObject = {
  myMethod: function () {
    helperObject.doSomethingCool('superCool',
      this.onSomethingCoolDone);
    },

    onSomethingCoolDone: function () {
      /// Only god knows what is "this" here
    }
};

Посмотрите на код. Вы можете подумать, что, потому что мы проезжаем Это. Подсветитесь к тому, что классно-кладки В качестве обратного вызова сфера есть MyObject Ссылка на этот метод, а не к способу назвать его.

Чтобы исправить это, есть несколько способов:

  • Обычно библиотеки предлагают другой параметр, поэтому вы можете передать объем, который вы хотите вернуться.
myObject = {
  myMethod: function () {
    helperObject.doSomethingCool('superCool', this.onSomethingCoolDone, this);
  },

  onSomethingCoolDone: function () {
    /// Now everybody know that "this" === myObject
  }
};
  • Вы можете привязывать метод к применению, который вы хотите (ES5).
myObject = {
  myMethod: function () {
    helperObject.doSomethingCool('superCool', this.onSomethingCoolDone.bind(this));
  },

  onSomethingCoolDone: function () {
    /// Now everybody know that "this" === myObject
  }
};
  • Вы можете создать закрытие и кеш это в я Отказ Например:
myObject = {
  myMethod: function () {
    var me = this;

    helperObject.doSomethingCool('superCool', function () {
      /// Only god knows what is "this" here, but we have access to "me"
    });
  }
};

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

Эта проблема применяется также к слушателям события, тайм-аута, Foreach и т. Д.

Соответствующие учебные пособия, которые вас могут быть заинтересованы в

  • JavaScript лучшие практики: Советы и хитрости навыки вашего кода
  • От 0 до 9: магия чисел в JavaScript
  • == vs: двойные равны и принуждение