2013-05-18 107 views
2

我已經實現了封裝與外部設備交互的驅動程序的對象。當駕駛員接收到數據時,它會發出一個事件。爲發出的事件創建偵聽器時發生關閉問題

當我開始時,我加載一個所有定義的驅動程序的列表。然後,我遍歷的定義,以做到以下幾點:

  • 創建一個驅動程序實例,
  • 偵聽司機的事件,並
  • 告訴司機進行連接。

作爲發出事件的偵聽器的一部分,我定義了一個函數,它傳遞設備表示的一些細節。

但是我的代碼似乎有問題。當一個驅動程序發出一個事件時,被觸發的函數只顯示一組細節。這些細節是在for循環中定義的最後一個,我創建驅動程序並監聽事件。

我創建了一個測試示例,通過使用幾個簡單對象和計時器來重新創建我的問題。這需要在node.js中運行以查看問題。

var EventEmitter = require('events').EventEmitter; 
var util   = require('util'); 

// define vehicle object 
function Vehicle(options) { 
    options = options || {}; 
    this.id = ((options.id != null) ? options.id : -1); 
    this.name = ((options.name != null) ? options.name : 'unknown'); 
} 

util.inherits(Driver, EventEmitter); 

// define driver object 
function Driver(options) { 
    options = options || {}; 
    this.id = ((options.id != null) ? options.id : -1); 
    this.name = ((options.name != null) ? options.name : 'unknown'); 
} 

Driver.prototype.startTimer = function(delay) { 
    self = this; 

    console.log('starting timer for ' + self.name + ' with a delay of ' + delay); 

    setTimeout(function() { 
     console.log('firing timer for ' + self.name); 
     self.emit('timer', 'some data'); 
    }, delay); 
} 

// function to create listener 
function makeOnTimerFunction(driver, vehicle) { 
    console.log("creating function for d name : " + driver.name + ' d id: ' + driver.id + ' v id: ' + vehicle.id + ' v name: ' + vehicle.name); 
    return function(d) { 
     console.log(" d name: " + driver.name + ' d id: ' + driver.id + ' v id: ' + vehicle.id + ' v name: ' + vehicle.name + ' d: ' + d); 
    } 
} 

var vehicles = new Array(); 
vehicles.push(new Vehicle({id: 1001, name: 'Max'})); 
vehicles.push(new Vehicle({id: 1002, name: 'Cheif'})); 
vehicles.push(new Vehicle({id: 1003, name: 'Seigfreid'})); 
var driver = null; 

for (var i = 0; i < 3; i++) { 

    driver = new Driver({ 
     id: vehicles[i].id, 
     name: vehicles[i].name, 
    }); 

    driver.on('timer', makeOnTimerFunction(driver, vehicles[i])); 
    driver.startTimer(1000 * i); 
} 

```

我得到的輸出如下:

creating function for d name : Max d id: 1001 v id: 1001 v name: Max 
starting timer for Max with a delay of 0 
creating function for d name : Cheif d id: 1002 v id: 1002 v name: Cheif 
starting timer for Cheif with a delay of 1000 
creating function for d name : Seigfreid d id: 1003 v id: 1003 v name: Seigfreid 
starting timer for Seigfreid with a delay of 2000 
firing timer for Seigfreid 
d name: Seigfreid d id: 1003 v id: 1003 v name: Seigfreid d: some data 
firing timer for Seigfreid 
d name: Seigfreid d id: 1003 v id: 1003 v name: Seigfreid d: some data 
firing timer for Seigfreid 
d name: Seigfreid d id: 1003 v id: 1003 v name: Seigfreid d: some data 

我希望看到的是如下:

creating function for d name : Max d id: 1001 v id: 1001 v name: Max 
starting timer for Max with a delay of 0 
creating function for d name : Cheif d id: 1002 v id: 1002 v name: Cheif 
starting timer for Cheif with a delay of 1000 
creating function for d name : Seigfreid d id: 1003 v id: 1003 v name: Seigfreid 
starting timer for Seigfreid with a delay of 2000 
firing timer for Max 
d name: Max d id: 1001 v id: 1001 v name: Max d: some data 
firing timer for Chief 
d name: Chief d id: 1002 v id: 1002 v name: Chief d: some data 
firing timer for Seigfried 
d name: Seigfreid d id: 1003 v id: 1003 v name: Seigfreid d: some data 

的問題是,定時器始終引用最後一個名爲Seigfreid的對象。

---- ----編輯

只是爲了使問題明確問題似乎是與makeOnTimerFunction功能。它返回的函數是發生事件時觸發的函數。當調用makeOnTimerFunction時,變量都是有意義的。但是,當事件觸發並調用makeOnTimerFunction返回的函數時,變量總是相同的。當第一次調用makeOnTimerFunction時,它們不會反映這些值。

+0

你試過關閉了在最後'for'循環的'i'? – kieran

+0

我不確定你的意思基蘭對不起,我已經做了一些關於關閉的閱讀,並認爲我正在處理所有的變量沒關係。 – Metalskin

回答

2

這是你的問題:

Driver.prototype.startTimer = function(delay) { 
    self = this; <---- 

你有效地創建一個全局變量self,其中被覆蓋每次運行startTimer方法的時間。最後,它會被覆蓋,因此它指向最後一個驅動程序實例,因此您的意外結果。

解決方法:使用var創建一個新的變量作用域方法:

Driver.prototype.startTimer = function(delay) { 
    var self = this; 
+0

感謝羅伯特,原因有點令人尷尬,但感謝你找到它。 :-) – Metalskin

相關問題