Ответ 1
Существует три основных способа обработки this
в обратных вызовах:
1. Создайте переменную с лексической областью, как вы сейчас делаете
Два наиболее распространенных имени для этой новой переменной: that
и self
. Я лично предпочитаю использовать that
, потому что у браузеров есть глобальное свойство окна, называемое self, и мой linter жалуется, если я его тень.
function edit(req, res) {
var that = this,
db.User.findById('ABCD', function(err, user){
that.foo(user);
});
};
Одним из преимуществ этого подхода является то, что после преобразования кода в использование that
вы можете добавить столько внутренних обратных вызовов, сколько захотите, и все они будут легко работать из-за лексического охвата. Другим преимуществом является то, что его очень простая и будет работать даже в древних браузерах.
2. Используйте метод .bind().
Функции Javascript имеют метод .bind()
, который позволяет создать версию из них с фиксированным this
.
function edit(req, res) {
db.User.findById('ABCD', (function(err, user){
this.foo(user);
}).bind(this));
};
Когда дело доходит до обработки this
, метод связывания особенно полезен для одного из обратных вызовов, когда добавление функции обертки будет более подробным:
setTimeout(this.someMethod.bind(this), 500);
var that = this;
setTimeout(function(){ that.doSomething() }, 500);
Основным недостатком bind
является то, что если у вас есть вложенные обратные вызовы, вам также нужно вызвать bind
на них. Кроме того, IE <= 8 и некоторые другие старые браузеры, не внедряют метод bind
, поэтому вам может потребоваться использование shimming library, если вам все равно придется их поддерживать.
3. Если вам нужно более мелкомасштабное управление функциями или аргументами функции, вернитесь к .call() и .apply()
Более примитивными способами управления параметрами функции в Javascript, включая this
, являются .call()
и .apply()
. Они позволяют вам вызывать функцию с любым объектом в качестве this
и любыми значениями в качестве параметров. apply
особенно полезен для реализации вариационных функций, поскольку он получает список аргументов как массив.
Например, вот версия bind, которая получает метод для привязки в виде строки. Это позволяет нам записать this
только один раз, а не дважды.
function myBind(obj, funcname){
return function(/**/){
return obj[funcname].apply(obj, arguments);
};
}
setTimeout(myBind(this, 'someMethod'), 500);