Как данные передаются анонимным функциям в JavaScript? - PullRequest
5 голосов
/ 24 мая 2009

Когда я передаю 'this' анонимной функции, например:

MyClass.prototype.trigger = function(){
    window.setTimeout(function(){this.onTimeout();},1000);
}

Я получаю ошибку "this.onTimeout не является функцией". Я предполагаю, что «this» больше не доступно во время выполнения анонимной функции? Итак, я делаю это:

MyClass.prototype.trigger = function(){
    var me = this
    window.setTimeout(function(){me.onTimeout();},1000);
}

Это действительно, как вы должны делать вещи? Это вроде работает, но кажется странным.

Тогда у нас есть этот пример:

$(function(){
    function MyClass(){
        this.queue = new Array();
    }
    MyClass.prototype.gotAnswer = function(count){
        $('body').append("count:"+count+"<br/>");
    }
    MyClass.prototype.loadAll = function(){
        var count = 0;
        var item;
        while(item = this.queue.pop()){
            count++;
            var me = this;
            $.getJSON("answer.html",{},function(data){me.gotAnswer(count);});
        }
    }

    var o = new MyClass();
    o.queue.push(1);
    o.queue.push(2);
    o.loadAll();

});

Это выводит:

2
2

Не должен ли он выводить:

1
2

вместо этого? Затем я обнаружил, что помещение оператора $ .getJSON в другую функцию заставляет все это работать:

MyClass.prototype.loadAll = function(){
    var count = 0;
    var item;
    while(item = this.queue.pop()){
        count++;
        this.newRequest(count);
    }
}
MyClass.prototype.newRequest = function(count){
    var me = this;
    $.getJSON("answer.html",null,function(data){ me.gotAnswer(count); });
}

Это выводит:

1
2

(Или наоборот.) Что здесь происходит? Как правильно передать переменные в анонимную функцию?

Извините за запутанный и длинный пост.

Ответы [ 3 ]

5 голосов
/ 24 мая 2009

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

  1. Обычный вызов функции
    myFunc(param1, param2);
    Этот способ вызова функции всегда сбрасывает «this» в глобальный объект. Вот что происходит в вашем случае.
  2. Вызов этого метода
    myObj.myFunc(param1, param2);
    Неудивительно, что «this» устанавливает объект, для которого вызывается метод. Здесь "this" == "myObj".
  3. Вызов метода Apply
    myFunc.apply(myObj, [param1, param2])
    Это интересный - здесь «this» задается для объекта, который вы передаете в качестве первого параметра метода apply - это похоже на вызов метода для объекта, у которого нет этого метода ( будьте осторожны, чтобы функция была написана так, чтобы она вызывалась так). Все функции по умолчанию имеют метод apply.
  4. Как конструктор (с «новым»)
    myNewObj = new MyConstructor(param1, param2);
    Когда вы вызываете функцию таким способом, «this» инициализируется новым объектом, который наследует методы и свойства из свойства прототипа вашей функции. В этом случае новый объект будет наследоваться от MyConstructor.prototype. Кроме того, если вы не вернете значение явно, будет возвращено «this».

Решение, которое вы использовали, является рекомендуемым решением - присвойте внешнее значение «this» другой переменной, которая все еще будет видна внутри вашей функции. Единственное, что я хотел бы изменить, - это назвать переменную «то», как говорит Тёрек Габор, - это своего рода стандарт де-факто, и он может сделать ваш код легче для чтения другими программистами.

3 голосов
/ 24 мая 2009

Вы запутались в замыканиях.

Что касается первой проблемы, да, вы правы, это то, как это можно сделать. Единственное отличие состоит в том, что существует соглашение о присвоении переменной that значения this.

.
MyClass.prototype.trigger = function(){
    var that = this;
    window.setTimeout(function(){that.onTimeout();},1000);
}

На StackOverflow уже есть хорошая ветка об этом. Проверьте ответы на вопрос Как работает закрытие JavaScript? .

Ваша вторая проблема - точная копия Закрытие Javascript внутри циклов - простой практический пример .

0 голосов
/ 05 декабря 2013

у вас будет та же проблема, если внутри вашего нового метода: newRequest вы должны использовать оператор for или while. Другим решением может быть создание замыкания:

вот так:

$.getJSON("answer.html",{},(function(me){return function(data){me.gotAnswer(count);}})(this));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...