2012-10-11 50 views
3

我想通过使用mixin拆分一个大类。在Coffeescript中使用mixins

我用这混入代码从Little Book

@include: (obj) -> 
    for key, value of obj when key not in moduleKeywords 
     # Assign properties to the prototype 
     @::[key] = value 

    obj.included?.apply(@) 
    this 

class FooMixin 

    b: => @something = 2 

class Foo extends Module 
    @include FooMixin 

    a: => @something = 1 

问题是,在@是​​​​。我希望它是Foo

我曾尝试在@include()的末尾添加_.bind(@::[key], @)行,但它没有帮助。有什么建议么?

回答

3

好吧,我做错了一些事情。

1.

@include从小书需要对象不是类。为了让它与课程一起工作,您需要编写@include FooMixin::。不过,我从此开始使用对象。

2.

当使用对象,而不是一类,脂肪右箭头在其读取_this = this顶部添加CoffeeScript的包装器中的线。所有方法都绑定到全局上下文,而这并不是我们想要的。要修复,我们必须将胖箭头转换为细箭头,并将每个函数绑定到我们的Foo实例。使用下划线我已将此添加的Foo构造:

constructor: -> 
    for fname in _.functions FooMixin 
    @[fname] = _.bind @[fname], @ 
    super 

我试图_.bindAll @, _.functions FooMixin,但它给了我一个错误说像At Function.bind, could not run bind of undefined.奇怪的错误,看到上面的代码是几乎等同于_.bindAll方法。

所以,现在我可以将我的课程拆分为更好的可读性和代码共享。


UPDATE:与_.bindAll的问题是,它需要一个图示不是一个数组。修正是使用_.bindAll @, _.functions(FooMixin)...

更新:找到了更好的解决方案。

与原文相同。为mixin使用类。

使用@include FooMixin::或更改@include来操作原型而不是属性。

Foo构造函数中编写FooMixin.call @它正确地绑定了这些方法。

这工作得很好,很干净。

唯一的潜在问题是mixin将被现有属性覆盖。要解决这个问题,我可以看到的唯一方法是做这样的事情:

after = -> 
    _.extend Foo, FooMixin:: 

class Foo 
    # define... 

after() 

或者通过扩展方法_.defer但这是如此哈克,可能将无法正常工作。

+0

对于任何可能使用backbone.js(或underscore.js)的人来说,已经有一个方法在模型上定义了一个名为['extend'](http://backbonejs.org/#Model-extend)的方法这将与这里描述的相冲突。如果你发现你遇到了各种各样的问题,请尝试将它重命名为其他内容 - 这对我有用。 –