2012-06-15 43 views
3

我正在编写一个骨干应用程序,并且我想写一个经过身份验证的装饰器,我可以用它来装饰路由器类中的一组方法(路由)。在CoffeeScript类中装饰函数

所以我有一个路由器有几个方法,并尝试过这样的事情。然而,当我打电话给我想要装饰的路线时,修饰器并未连接。

class MyApp extends Backbone.Router 

    routes: 
    ''   : 'home' 
    'foo'  : 'foo' 
    'bar'  : 'bar' 


    authenticated: ['foo', 'bar'] 

    initialize: -> 
    @decorateAuthenticatedFunctions()  

    decorateAuthenticatedFunctions: => 
    _.each @authenticated, (method)=> 
     @[method] = (args)=> 
     if @authorized() 
      @[method].apply @, args 
     else 
     @navigate '', true 

    authorized: => 
    @user? and @user.loggedIn 

    foo: => 
    #do stuff 

    bar: => 
    #do stuff 

如何解决此问题?

+0

确定'initialize'被称为呢?在那里添加一个console.log的警报。 –

回答

0

我认为你有一个this上下文问题。

请记住,“胖箭头”=>在函数定义时绑定到this。所以你的decorateAuthenticatedFunctions: =>绑定到全球this,当你想要绑定它到你的MyApp实例。

试试这个:

... 

initialize: -> 
    @decorateAuthenticatedFunctions.call(@) # Call with proper context 

decorateAuthenticatedFunctions: -> # Use skinny arrow 
    _.each @authenticated, (method)=> 
    @[method] = (args)=> 
     if @authorized() 
     @[method].apply @, args 
     else 
     @navigate '', true 

authorized: ->      # Use skinny arrow 
    @user? and @user.loggedIn 

... 
+0

方法声明上的'=>'工作方式不同。相反,它确保'这个'永远是实例。 http://coffeescript.org/#try:class%20Foo%0A%20%20foo%3A%20%3D%3E –

+0

嗯...我认为你是对的。我仍然建议通过在decorateAuthenticatedFunctions顶部调试和断开分析'this'上下文。 –

3

你有几个问题。

首先,我不认为initialize由于某种原因而被调用。我可以说,因为如果它被调用,那么它会引发错误(请参阅下一点)。现在我不是骨干专家,但也许尝试使用构造函数呢?

class MyApp extends Backbone.Router 
    constructor: -> 
    super 
    @decorateAuthenticatedFunctions() 

其次,该循环不会工作。您将用新函数替换@[method],该函数在该函数中调用@[method]。当它成功时,你会得到一个递归的无限函数调用。因此保存对原始函数的引用,然后使用装饰器函数调用该引用。

虽然你在那里,但不需要下划线,因为咖啡脚本确实循环很好。你甚至不需要关闭这个循环,因为你只是立即使用循环值。

这稍微改变非骨干版本的作品:

http://jsfiddle.net/ybuvH/2/

class MyApp 

    authenticated: ['foo', 'bar'] 

    constructor: -> 
    @decorateAuthenticatedFunctions()  

    decorateAuthenticatedFunctions: => 
    for method in @authenticated 
     fn = @[method] 
     @[method] = (args) => 
     if @authorized() 
      fn.apply @, args 
     else 
      console.log 'denied' 

    authorized: => 
    @user? and @user.loggedIn 

    foo: => 
    console.log 'foo' 

    bar: => 
    console.log 'bar' 

app = new MyApp 

app.user = { loggedIn: no } 
app.foo() # denied 
app.bar() # denied 

app.user = { loggedIn: yes } 
app.foo() # foo 
app.bar() # bar​ 

+0

你不想提供你自己的'constructor'。骨干机器将调用'initialize'。尽管如此,他错过了他的'else'缩进,这可能会导致一些意想不到的行为。使用'_.each'有一个优点,即如果可用,将使用本地'forEach'。 –