Javascript обратные вызовы теряют 'this'
У меня есть эмитент, где я теряю 'this' внутри этого "объекта". Вывод следующего фрагмента javascript дает мне "some-id", а затем "undefined". Когда я использую 'this' внутри функции обратного вызова, область выходит за пределы объекта и больше не может использовать 'this'. Как я могу получить обратный вызов для использования 'this' или, по крайней мере, иметь доступ к объекту?
Так как я создам несколько объектов, я не смогу создать "статичное" хранилище. Пожалуйста, помогите этому javascript n00b; -)
вот мой тестовый код, который вы можете использовать для воспроизведения моей проблемы. Я бы хотел, чтобы CheckBox.doSomething()
возвращал значение this.id
, которое должно соответствовать some-id
для этого тестового примера.
function CheckBox(input_id) {
this.id = input_id;
this.doSomething();
$('#some-element').click(this.doSomething);
}
Checkbox.prototype.doSomething = function() {
alert(this.input_id);
}
var some_box = new CheckBox('some-id');
some_box.doSomething();
$('#some-element').click();
edit: Я даже не могу заставить это работать так, как хочу:
function CheckBox2(input_id) {
this.id = input_id;
alert(this.id);
}
CheckBox2.prototype.doSomething = function() {
alert(this.input_id);
}
var some_box = new CheckBox2('some-id');
some_box.doSomething();
Ответы
Ответ 1
function CheckBox(input_id) {
this.id = input_id;
this.doSomething = $.proxy( this.doSomething, this );
$('#some-element').click(this.doSomething);
}
"эквивалент javascript" этого Function#bind
, но это не доступно в каждом браузере, и поскольку кажется, что вы используете jQuery, я использую эквивалент jQuery $.proxy
Ответ 2
Ваша проблема в этой строке: $('#some-element').click(this.doSomething);
Почему это проблема
Методы JavaScript ничего не знают об объекте, который должен быть назначен this
, он устанавливается, когда метод вызывается явно (с помощью myFunction.call(obj)
) или неявно (при вызове с использованием obj.myFunction()
).
Например:
var x = {
logThis: function () {
console.log(this);
}
};
x.logThis(); // logs x
x.logThis.call(y); // logs y
var func = x.logThis;
func(); // logs window: the fallback for when no value is given for `this`
В вашем случае вы передаете this.doSomething
в jQuery, который затем явно вызывает его с элементом, который был нажат как значение this
. Что происходит (немного более сложная версия):
var callback = this.doSomething;
callback.call(anElement, anEvent);
Решение
Вам нужно убедиться, что doSomething
вызывается с правильным значением this
. Вы можете сделать это, обернув его другой функцией:
var cb = this;
$('#some-element').click(function() {
return cb.doSomething();
});
jQuery предоставляет функцию proxy
, которая позволяет сделать это проще:
$('#some-element').click(jQuery.proxy(this.doSomething, this));
Ответ 3
Другие уже объяснили причины проблемы и как ее исправить с помощью jQuery. Осталось то, как вы исправляете его со стандартным JavaScript. Вместо...
$('#some-element').click(this.doSomething);
... вы пишете:
$('#some-element').click(this.doSomething.bind(this));
Это изменяет контекст this
внутри doSomething
. Вы также можете сделать это с анонимными функциями - вместо...
$('some-element').click(function(event) {
console.log(this);
});
... вы пишете:
$('some-element').click((function(event) {
console.log(this);
}).bind(this));
Это было очень полезно для меня в проектах с большим количеством обратных вызовов, например. в Node.js(где вам не нужно заботиться об устаревших браузерах).