2013-05-21 27 views
1

我有一個類MyClass接受對象作爲方法附加到它。這些方法調用MyClass.push將數據添加到對象的內部@_list陣列。兩個相同的測試案例的第二個失敗,但我不明白爲什麼:爲什麼在第一次之後發生同樣的摩卡測試失敗?

chai = require "chai" 
chai.should() 

obj = 
    name: 'foo' 
    f: -> 
    for i in [1..5] 
     @push "Element #{i}" 


class MyClass 
    constructor: (@options) -> 
    @methods = {} 
    @_list = [] 

    if 'attach' of @options 
     @attach @options.attach 

    push: (m) -> 
    @_list.push m 

    list: -> 
    @_list 

    method: (v) -> 
    @methods[v].f 

    run: (options) -> 
    @method('foo')() 

    attach: (o) -> 
    @methods[o.name] = o 
    @methods[o.name].f = o.f.bind(@) 

describe 'MyClass', -> 
    it 'list should have five elements', -> 
    v = new MyClass attach: obj 
    v.run() 
    v.list().length.should.equal 5 
    it 'list should have five elements (#2)', -> 
    v = new MyClass attach: obj 
    v.run() 
    v.list().length.should.equal 5 

我相信這是與功能結合去,因爲當我更換第二v = new MyClass attach: obj

v = new MyClass attach: 
    name: 'foo' 
    f: -> 
    for i in [1..5] 
     @push "Element #{i}" 

這兩個測試都通過了。但我不明白這種行爲,因爲我認爲.bind()創建函數的副本。那麼這裏發生了什麼,以及如何讓兩個測試獨立運行?

回答

1

JavaScript(以及因此coffeescript)對象是通過引用。當您啓動第二次測試,您obj對象已經改變,因爲你已經修改了它的f屬性做:

@methods[o.name].f = o.f.bind(@)

你可以通過它的一個副本,而不是避免這種情況。

+0

我覺得我應該明白這一點,但我沒有(儘管我正在努力!)。這5個元素設置爲'v',而不是'obj'。我想保持數組內部的每個對象('v'),但是'obj'(包含函數)需要能夠在'MyClass'的不同實例之間共享。我在這裏假設@push指的是'obj'附加的'v'。我有道理嗎? – user2010963

+1

@ user2010963因爲'obj'是通過引用傳遞的,當你通過'@methods [o.name] .f = o.f.bind(@)'將'o.f'綁定到第一個對象時,你正在改變obj。這是你的代碼更正http://codepen.io/anon/pen/JlGyq。另外,我很抱歉,我最初的回答是錯誤的。 –

相關問題