2013-05-21 28 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。另外,我很抱歉,我最初的回答是错误的。 –

相关问题