Проблема привязки объекта Javascript внутри определений прототипов функций

Я пытаюсь найти правильное место для привязки прототипа функции, который будет вызываться позже. Полный код примера можно найти здесь:

http://www.iprosites.com/jso/

Мой пример javascript очень прост:

function Obj(width, height){
    this.width = width;
    this.height = height;
}

Obj.prototype.test = function(){
    var xhr=init();
    xhr.open('GET', '?ajax=test', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    xhr.onreadystatechange = function() {
        if (xhr.responseText == '403') {
            window.location.reload(false);
        }
        if (xhr.readyState == 4 && xhr.status == 200) {
            this.response = parseResponse(xhr.responseText);
            document.getElementById('resp').innerHTML = this.response.return_value;
            this.doAnotherAction();
        }
    };
    xhr.send();
}

Obj.prototype.doAnotherAction = function(){
    alert('Another Action Done');
}


var myo = new Obj(4, 6);

Если вы попытаетесь запустить myo.test() в Firebug, вы получите ответ «this.doAnotherAction не является функцией». Две вспомогательные функции init() и parseResponse() можно найти по ссылке test.js, если вы хотите их просмотреть, но они не должны иметь большого отношения к этой проблеме. Я подтвердил, что this.doAnotherAction() считает, что "это" является объектом XMLHttpResponse, как и ожидалось от теста instanceof.

Может ли кто-нибудь помочь с некоторым пониманием направления с привязкой? Все, что я пробовал, кажется, не работает!

Я использую Mootools, хотя библиотеки в этом примере нет.

Заранее спасибо,

Арион


person Arion    schedule 10.06.2010    source источник


Ответы (2)


this внутри xhr.onreadystatechange не относится к экземпляру Obj. вам нужно захватить this вне функции в локальной переменной, а затем использовать ее внутри xhr.onreadystatechange. то есть

Obj.prototype.test = function(){
    var obj = this,
        xhr=init();
    xhr.open('GET', '?ajax=test', true);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
    xhr.onreadystatechange = function() {
        if (xhr.responseText == '403') {
            window.location.reload(false);
        }
        if (xhr.readyState == 4 && xhr.status == 200) {
            this.response = parseResponse(xhr.responseText);
            document.getElementById('resp').innerHTML = this.response.return_value;
            obj.doAnotherAction();
        }
    };
    xhr.send();
}

Проверьте это на своей тестовой странице, вставив приведенное выше в консоль, а затем запустив myo.test() :)

person Russ Cam    schedule 10.06.2010
comment
хорошо сын пистолета, это работает, когда я делаю это. Это просто кажется немного наигранным, чтобы избежать надлежащего использования привязки функций, не так ли? Я благодарен, что вы предоставили рабочий ответ, но нет ли случайно каких-либо мыслей о характере привязки в этом случае? Благодаря тонну!!! :) - person Arion; 11.06.2010
comment
что вы подразумеваете под правильным использованием привязки функций? Контекст функции внутри анонимной функции, назначенной onreadystatechange (т. е. this), представляет собой объект xmlHttpRequest. Без применения функции с контекстом экземпляра Obj (как в ответе Анурага) я не думаю, что это можно обойти. Поэтому вам нужно зафиксировать внешний контекст в переменной и использовать эту переменную внутри внутренней функции. - person Russ Cam; 11.06.2010

ECMAScript 5-е изд. позаимствовал метод bind для функций из среды Prototype. Вы можете включить его в свой код, который определит метод привязки, если он еще не присутствует.

if (!Function.prototype.bind)
{
    Function.prototype.bind = function() {
        var fn = this, 
            args = Array.prototype.slice.call(arguments), 
            object = args.shift();

        return function() {
            return fn.apply(object,
                args.concat(Array.prototype.slice.call(arguments)));
        };
    };
}

После определения вы можете связать анонимную функцию внутри обратного вызова onreadystatechange с объектом Obj.

xhr.onreadystatechange = function() {
    ...
}.bind(this);
person Anurag    schedule 11.06.2010
comment
ааа, хорошо, моя проблема раньше заключалась в том, что я пытался добавить bind(this) в методы test() или doAnotherAction(), когда я должен был привязать это к обратному вызову onreadystatechange. - person Arion; 11.06.2010