2

У меня есть модель файл, который расслоение плотной выглядитGoogle Closure: Передача «это» в Window.setInterval

goog.provide('model.ErrorLogger'); 
/** 
* @constructor 
*/ 
model.ErrorLogger = function() { 
    window.onerror = goog.bind(this.errorHandler, this); 
    this.doInitialSend(); 

}; 
goog.addSingletonGetter(model.ErrorLogger); 

model.ErrorLogger.prototype.ws_ErrLgr_config = true; 

model.ErrorLogger.prototype.doInitialSend = function(){ 
    if (this.ws_ErrLgr_config){ 
     window.setInterval(this.sendReport, this.ws_ErrLgr_config); 
    } 

}; 

model.ErrorLogger.prototype.sendReport = function(){ 
    // the value of 'this' needs to be of the ErrorLogger model and not windows 
    if (!this.ws_ErrLgr_config || this.stopped) { 
      //some more code here 
    } 
} 

В конструкторе я вызываю функцию doInitialSend установившее window.setInterval. Теперь в функции sendReport значение «this» неверно. Как правильно передать «это», чтобы получить правильное значение, а не получать окно. Я попытался сохранить значение этого в ссылке, но это тоже не сработало. Например

var that = this; 
window.setInterval(that.sendReport, that.ws_ErrLgr_config); 

ответ

4

идиоматических способ сделать это в Google Closure использует goog.bind, с тем преимуществом, что это гарантировано, что это всегда будет работать. Плюс он будет использовать Function.prototype.bind() под капотом, когда это доступно.

В этом случае решение будет:

myIntervalInMilliseconds = 1000; // One second. 
window.setInterval(goog.bind(this.sendReport, this), myIntervalInMilliseconds); 

Использование that = this работ, но требует, чтобы вы явно обернуть функцию в другой, чтобы захватить that, как this в нужную функцию.

Для этого лучше использовать Function.prototype.bind(), как указано в других ответах. Однако это не сработает, если вы хотите поддерживать старые браузеры (IE < 9).


PS: Еще одна проблема в вашем коде является то, что он использует this.ws_ErrLgr_config как интервал, который установлен в true в прототипе. Это неверно, вы должны выбрать номер для представления вашего интервала.

+0

'goog.bind' - это просто pollyfill для' Function.prototype.bind'. Если браузер поддерживает привязку встроенных функций, 'goog.bind' будет использовать его. –

+0

Это действительно здорово. Огромное спасибо. –

0

Вы можете сделать это:

var that = this; 
window.setInterval(function() { 
    that.sendReport() 
}, this.ws_ErrLgr_config.ReportInterval); 

Таким образом, вы можете позвонить sendReport в правильном контексте, также это работает:

window.setInterval(this.sendReport.bind(this), this.ws_ErrLgr_config.ReportInterval); 

Причина window.setInterval(that.sendReport, this.ws_ErrLgr_config.ReportInterval) не работа заключается в том, что Javascript является передачей по значению. Выше утверждение эквивалентно:

window.setInterval(function(){ 
    // the value of 'this' needs to be of the ErrorLogger model and not windows 
    if (!this.ws_ErrLgr_config || this.stopped) { 
      //some more code here 
    } 
}, this.ws_ErrLgr_config.ReportInterval); 

С помощью .bind() ключевого слова или обернув его в другой функции, а затем отсылая к that от outerscope, вы можете вызвать функцию в требуемом объеме.

+0

прохладный тот работает. но как это делает лишняя функция? – rk8785

+0

'window.setInterval (that.sendReport, ...)' указывает на функцию sendReport в глобальной области видимости, потому что javascript передается по значению. Таким образом, обертывая его в другую функцию, а затем вызывая 'this.sendReport();' будет вызывать его в правильном контексте. –

0

Или это:

window.setInterval((function() { 
    this.sendReport(); 
}).bind(this), this.ws_ErrLgr_config.ReportInterval); 
+0

Да, это тоже работает. Короче будет: 'this.sendReport.bind (this)'. Но теперь вы забыли интервал. 'this.ws_ErrLgr_config.ReportInterval' –

+0

Вы правы, моя вина. Более короткая версия еще лучше. Должен ли я менять сообщение? – skypjack

+0

Все в порядке, тем веселее. Всегда интересно видеть различные подходы к решению проблемы. –