2012-06-15 51 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'。 –