Автор оригинала: 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: двойные равны и принуждение