3

我看到在CoffeeScript中/有關的NodeJS和EventEmitters處理一些很奇怪的行爲。我已經把它表現出的問題,一個小樣本...爲什麼我無法將事件處理程序2委託給深層?

基本上我有我的事件處理一些間接的,但我似乎無法得到它的工作,除非我包的第一個事件處理程序的拉姆達,我想了解爲什麼/如果有什麼我可以做的,以使這項工作。根據我的想法,基本上test1()應該與test3()具有相同的行爲。包含test2()只是爲了表明事件處理的第二級工作!

events = require "events" 

class ExampleEmitter extends events.EventEmitter 
    constructor:() -> 
    go1:() -> 
     console.log("fire 1") 
     @emit("test1", "there") 
    go2:() -> 
     console.log("fire 2") 
     @emit("test2", "there") 

class ExampleHandler 
    constructor:() -> 
    handle: (x) -> console.log("hey", x) 

test1 =() ->   
    handler = new ExampleHandler() 
    emitter1 = new ExampleEmitter() 
    emitter2 = new ExampleEmitter() 
    emitter1.on "test1", emitter2.go2 
    emitter2.on "test2", handler.handle #this doesn't fire :(
    emitter1.go1() 

test2 =() ->   
    handler = new ExampleHandler() 
    emitter1 = new ExampleEmitter() 
    emitter2 = new ExampleEmitter() 
    emitter1.on "test1", emitter2.go2 
    emitter2.on "test2", handler.handle 
    emitter2.go2() 

test3 =() ->   
    handler = new ExampleHandler() 
    emitter1 = new ExampleEmitter() 
    emitter2 = new ExampleEmitter() 
    emitter1.on "test1",() -> emitter2.go2() #why must I wrap this? 
    emitter2.on "test2", handler.handle 
    emitter1.go1() 

console.log "\ntest1" 
test1() 
console.log "\ntest2" 
test2() 
console.log "\ntest3" 
test3() 

這是輸出:

test1 
fire 1 
fire 2 

test2 
fire 2 
hey there 

test3 
fire 1 
fire 2 
hey there 

回答

5

emitter1.on "test1",() -> emitter2.go2() #why must I wrap this?

因爲如果你只是傳遞emitter2.go2,GO2會在根對象的上下文被稱爲(window在瀏覽器中;我不太瞭解node.js)而不是emitter2。一個函數本身並不知道它所屬的對象。事實上,您應該通過一個關閉窗口打電話給on

爲了讓事情看起來更好一點,你可以省略括號如果您關閉不帶任何參數。最後,你應該有一些看起來像這樣:

handler = new ExampleHandler() 
emitter1 = new ExampleEmitter() 
emitter2 = new ExampleEmitter() 
emitter1.on "test1", -> emitter2.go2() 
emitter2.on "test2", -> handler.handle() 
emitter1.go1() 

如果你還是不喜歡的樣子,未來最好的事情是通過創建這樣使用功能「綁定」功能,對象封閉。它也救不了你任何打字,雖然,我認爲它看起來醜陋,難以閱讀:

bindMethod = (obj, funcName) -> 
    -> obj[funcName].apply(obj, arguments) 

... 

emitter1.on "test1", bindMethod(emitter2, 'go2') 
emitter2.on "test2", bindMethod(handler, 'handle') 

最後,你可以使用脂肪箭頭=>創建類聲明中這樣的綁定方法,讓你可以按照你認爲合適的方式穿過它們。 go2: -> ...將成爲go2: => ...,&℃。但在這種情況下,我認爲這是一種奇怪的行爲。我會堅持通過關閉,因爲它使意義更清晰。

+1

說得好。每當你在JavaScript或CoffeeScript中發現錯誤時,你應該問的第一件事是:「這是什麼」? (或者'@',這是同義詞)。在這種情況下,我會繼續使用胖箭頭'=>'定義'go2'以將其綁定到實例,以便'this'總是意味着您想要的它來。 – 2011-03-31 00:51:11

+1

因爲這是_node_,所以你寧願做'emitter2.go2.bind(emitter2)'而不是重新創建'bindMethod'。 – matyr 2011-03-31 01:13:03

+0

很好的答案,謝謝!在這種情況下使用'=>''胖箭頭''的缺點/怪異行爲是什麼?這看起來正是我在找的東西,不是嗎? – nicolaskruchten 2011-03-31 03:18:48

1

我就添加其他的答案在這裏,儘管我已經接受了上述的一個,如果人們不讀評論...

我的問題的實際修復,以獲得行爲我要找的,是使用=>「胖箭頭」在我的類定義,而不是正常的->「細箭頭」像我一樣,到功能綁定到類的實例。所以:

class ExampleEmitter extends events.EventEmitter 
    constructor:() -> 
    go1:() => 
     console.log("fire 1") 
     @emit("test1", "there") 
    go2:() => 
     console.log("fire 2") 
     @emit("test2", "there") 
+0

起初我並不認爲這會起作用,但CoffeeScript在用於定義類的實例方法時似乎對胖箭頭有特殊處理。它定義了原型上的方法是正常的,但它實際上將'this.go1 = __bind(this.go1,this);'添加到您的構造函數中,將原型方法替換爲始終運行在實例。非常棘手的CoffeeScript,你滑溜的狐狸...... – 2011-03-31 17:12:26