Проблема определения объема с обратным вызовом Javascript - PullRequest
1 голос
/ 09 июня 2010

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

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall("read_some_data", { }, this.readSuccess, this.readFail);
}

SomeObject.prototype.readSuccess = function(response)
{
    this.data = response;
    this.someList = [];
    for (var i = 0; i < this.data.length; i++)
    {
      var systemData = this.data[i];
      var system = new SomeSystem(systemData);
      this.someList.push(system);
    }
    this.refreshList();
}

В основном SomeAjaxCall выполняет ajax-запрос данных. Если это работает, мы используем обратный вызов this.readSuccess, а если это не удается, this.readFail.

Я выяснил, что this в SomeObject.readSuccess является глобальным this (он же объект window), потому что мои обратные вызовы вызываются как функции, а не как методы-члены Насколько я понимаю, мне нужно использовать замыкания, чтобы сохранить «это», однако я не смог заставить это работать.

Если кто-то сможет показать мне, что я должен делать, я был бы очень признателен. Я все еще обдумываю, как работают крышки и, в частности, как они будут работать в этой ситуации.

Спасибо!

Ответы [ 3 ]

2 голосов
/ 09 июня 2010

Ваша проблема здесь не является точно проблемой закрытия или определения области.Проблема в том, что когда вы присваиваете this.readSuccess переменной, вы присваиваете саму функцию без какого-либо представления об объекте, которому она изначально принадлежит.

Таким же образом вы можете использовать обычныйв одиночку »и используйте его как метод объекта:

function hello() {
    alert("Hello "+this.planet);
}
var planet = "Earth";
hello(); // -> 'Hello Earth'

var Venus = {
    planet: "Venus"
};
hello.apply(Venus); // -> 'Hello Venus'
Venus.hello = hello;
Venus.hello(); // -> 'Hello Venus'

И ваша проблема может быть воспроизведена в этом примерепеременная и вызов ее в качестве метода этого .Что может быть сделано с закрытием, как продемонстрировал Пойнти.Поскольку я не знаю, что на самом деле делает SomeAjaxCall, трудно понять, действительно ли потеряно значение this и действительно ли нужно var obj = this.Скорее всего, это не так, поэтому вы можете быть в порядке с таким кодом:

var helloVenus = function() { Venus.hello() }
helloVenus(); // -> 'Hello Venus'

В вашем случае это будет ( edit: добавление аргументов, переданных в обработчик):

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall(
    "read_some_data",
    { },
    function () { this.readSuccess.apply(this, arguments) },
    function () { this.readFail.apply(this, arguments) }
  );
}

Как отмечалось ранее, в нескольких js-фреймворках предусмотрена функция bind для упрощения такого рода проблем.Но вам не нужен полный фреймворк только для этого: вот совершенно прекрасный метод Function#bind, который работает простым javascript:

Function.prototype.bind = function(obj) {
    var __method = this;
    var args = [];
    for(var i=1; i<arguments.length; i++)
        args.push(arguments[i]);
    return function() {
        var args2 = [];
        for(var i=0; i<arguments.length; i++)
            args2.push(arguments[i]);
        return __method.apply(obj, args.concat(args2));
    };
}

С помощью Function#bind вы можете написать:

SomeObject.prototype.refreshData = function()
{
  var read_obj = new SomeAjaxCall(
    "read_some_data",
    { },
    this.readSuccess.bind(this),
    this.readFail.bind(this)
  );
}
2 голосов
/ 09 июня 2010

Что ж, самое простое, что нужно сделать, это просто обернуть this.readSuccess в другую функцию:

SomeObject.prototype.refreshData = function()
{
  var obj = this;
  var read_obj = new SomeAjaxCall("read_some_data", { }, 
    function() { obj.readSuccess(); }, function() { obj.readFail(); });
}

Некоторые фреймворки Javascript предоставляют утилиту для «привязки» функции к объекту, которая простоозначает, что он создает одну из тех маленьких функций для вас.Обратите внимание, что переменная "obj" будет "запомнена" этими маленькими функциями, поэтому, когда ваши обработчики будут вызваны, ссылка "this" будет относиться к объекту, который использовался для вызова "refreshData".

0 голосов
/ 09 июня 2010

Следующий сайт, кажется, предполагает, что проблема может быть скорее в вашем "классовом" здании, чем в использовании. Если вы прочитаете «переписать с использованием свойств прототипа», они напишут, что этот конкретный метод структурирования «класса» будет поддерживать методы глобальными, а не на основе экземпляров. Возможно, другой метод создания?

http://devedge -temp.mozilla.org / ViewSource / 2001 / уп-JavaScript /

...