Ошибка JavaScript "не является функцией" при вызове определенного метода

Это мой код:

request_xml: function()
        {
        http_request = false;
                    http_request = new XMLHttpRequest();
                     if (http_request.overrideMimeType) 
                            {
                            http_request.overrideMimeType('text/xml');
                            }
                          if (!http_request)
                          {
                                return false;
                          }
                        http_request.onreadystatechange = this.response_xml;
                        http_request.open('GET', realXmlUrl, true);
                        http_request.send(null);
                        xmlDoc = http_request.responseXML;

},



response_xml:function ()
    {
        if (http_request.readyState == 4)
        {
            if(http_request.status == 404 && countXmlUrl<=3)
            {
                countXmlUrl++;

                realXmlUrl = xmlUrl[countXmlUrl];
                this.request_xml();
            }
            if (http_request.status == 200)
            {
                xmlDoc = http_request.responseXML;
                alert("need to update3");
                this.peter_save_data();
            }

        }
    },

peter_save_data:function()
    {
// removed function code
},

Странно, предупреждение срабатывает без проблем, но вызов функции под ним дает мне эту ошибку:

Error: this.peter_save_data is not a function

Вызов той же функции проклятия из другой функции в другом месте отлично работает.

Ответы

Ответ 1

Вы можете сделать это прямо перед тем, как вызвать генерацию XML.

var that = this;

и позже...

that.peter_save_data();

Поскольку this часто изменяется при изменении области с помощью новой функции, вы не можете получить доступ к исходному значению, используя его. Слияние с ним позволяет вам получить доступ к исходному значению этого.

Ответ 2

Один важный фрагмент головоломки, который отсутствует, - это вызов response_xml. Это важно, потому что это изменит то, что this (см. Комментарий Jared).

Помните, что this можно рассматривать как (грубо) "приемник вызова метода". Если response_xml передается непосредственно для использования в качестве обратного вызова, то, конечно, это не сработает - this, скорее всего, будет window.

Рассмотрим следующее:

var x = {f: function () { return this }}
var g = x.f
x.f() === x    // true
g() === x      // false
g() === window // true

Счастливое кодирование.


"Исправить", вероятно, просто изменить способ вызова response_xml. Существует множество способов сделать это (как правило, с закрытием).

Примеры:

// Use a closure to keep he object upon which to explicitly invoke the method
// inside response_xml "this" will be "that",
// which was "this" of the current scope
http_request.onreadystatechange = (function (that) {
   return function () { return that.response_xml() }
}(this)

// Or, alternatively,
// capture the current "this" as a closed-over variable...
// (assumes this is in a function: var in global context does not create a lexical)
var self = this
http_request.onreadystatechange = function () {
   // ...and invoke the method upon it
   return self.response_xml()
}

Лично я просто использовал jQuery или аналогичный; -)

Ответ 3

Если вы хотите поведение класса, используйте правильный синтаксис. Библиотеки, которые его используют, используют JSON для передачи параметра функции, которая делает класс из него.

function MyClass(CTOR paarams){
    var response_xml=function ()
    {
        if (http_request.readyState == 4)
        {
            if(http_request.status == 404 && countXmlUrl<=3)
            {
                countXmlUrl++;

                realXmlUrl = xmlUrl[countXmlUrl];
                this.request_xml();
            }
            if (http_request.status == 200)
            {
                xmlDoc = http_request.responseXML;
                alert("need to update3");
                this.peter_save_data();
            }

        }
    }

    var peter_save_data=function()
    {
       // removed function code
    }
}

var Test = new MyClass(somthing,another_something);
Test.response_xml();
//etc etc.

Или используйте библиотеки, такие как Mootools, где вы можете сделать это как JSON:

var T = new Class({
    response_xml:function ()
    {
        if (http_request.readyState == 4)
        {
            if(http_request.status == 404 && countXmlUrl<=3)
            {
                countXmlUrl++;

                realXmlUrl = xmlUrl[countXmlUrl];
                this.request_xml();
            }
            if (http_request.status == 200)
            {
                xmlDoc = http_request.responseXML;
                alert("need to update3");
                this.peter_save_data();
            }

        }
    },

    peter_save_data:function()
    {
      // removed function code
    }

});
var X = new T();//etc etc