передача параметра анонимной функции javascript

#javascript

#javascript

Вопрос:

У меня есть некоторый код javascript (внутри объекта) :

 toggle: function() {
    var me = this;
    var handler = function() { me.progress() };
    me.intervalId = setInterval(handler, me.intervalTime);
    //...More code
}
  

Я вроде как новичок в javascript, поэтому, насколько я могу судить, выполнение вышеуказанного фактически передает me переменную в анонимную функцию. Я хотел посмотреть, есть ли более декларативный способ сделать это? Я хотел что-то вроде:

 var handler = (function(o) { o.progress();})(this));
  

но, похоже, это не работает… Я что-то упускаю? Это тот случай, когда «так работает язык, поэтому просто объявите локальную переменную и разберитесь с ней»?

Обновить:

Источником моей проблемы было / остается мое неясное понимание области видимости и замыканий в javascript. Я нашел эту статью, которая поможет мне понять немного больше.

Комментарии:

1. Это не работает, потому что у вас их ) слишком много. Возможно, не var handler = (function(o) { o.progress();})(this); работает?

Ответ №1:

Вы можете использовать «.bind()»:

 var handler = function() { this.progress(); }.bind(this);
  

В новых браузерах есть «bind()», а в документах Mozilla есть надежная реализация, которую вы можете использовать для исправления старых браузеров.

Комментарии:

1. еще более краткое решение для моей ситуации var handler = this.progress.bind(this) . Спасибо за ваш вклад!

Ответ №2:

Причина

 var handler = (function(o) { o.progress();})(this));
  

не работает, потому что она просто немедленно вызывает функцию anon, следовательно, немедленно вызывает o.progress() и присваивает возвращаемое значение функции anon (неопределенное) handler . Вам нужно вернуть фактическую функцию из внешней функции:

 handler = (function(me){
    return function(){
        return me.progress();
    }
}(this));
  

С другой стороны, это эквивалентно и выглядит так же плохо, как и присвоение переменной (но все равно может быть полезно, особенно если это нужно сделать в цикле, с изменением i, а не с исправлением this).


Кстати, если в функции progress нет никаких вызовов this внутри нее, может быть достаточно простого выполнения handler = this.progress (без скобок).

Ответ №3:

Анонимная функция имеет доступ к me , поскольку она объявлена внутри внешней функции (the toggle function); она закрыта внешней функцией.

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

Если вы действительно хотите передать me явно, вы могли бы написать функцию, принимающую параметр, и заставить эту функцию возвращать анонимную функцию без параметров, но которая могла бы получить доступ к параметру функции-создателя:

 toggle: function() {
    var me = this;
    var handler = (function (o) { return function() { o.progress() }; })(me);
    me.intervalId = setInterval(handler, me.intervalTime);
    //...More code
}
  

Но это в основном добавляет слой перенаправления, на самом деле не делая его более разборчивым. Если вы не извлекаете эту создающую функцию извне:

 function createProgressHandler(o) {
    return function() {
        o.progress();
    };
}

// ...

toggle: function() {
    var me = this;
    var handler = createProgressHandler(me);
    me.intervalId = setInterval(handler, me.intervalTime);
    //...More code
}
  

Ответ №4:

То, что у вас есть, — это закрытие. Функция, которая создается и назначается handler , сохраняет ссылку на me объект. Это обычный JavaScript, и именно так обычно работают замыкания.

Комментарии:

1. Это не его проблема. Он жалуется, что this не может быть закрыт, что вынуждает его var me = this .

2. Я согласен, но то, что он хочет сделать, равносильно борьбе с языком. Я — и, вероятно, все остальные, кто пишет код JavaScript — хотели бы обойтись без назначения локальной переменной, но это то, что есть.

Ответ №5:

Вы пытались вернуть функцию подобным образом?

 var handler = function(o){
   return function(){
      o.progress();
   }
}(me);
  

Теперь вы можете вызвать:

 handler();