Подтвердить что ты не робот

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();
4b9b3361

Ответ 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(где вам не нужно заботиться об устаревших браузерах).