装饰 CoffeeScript 类中的函数

Decorate functions in a CoffeeScript class

本文关键字:函数 CoffeeScript 装饰      更新时间:2023-09-26

我正在编写一个主干应用程序,我想编写一个经过身份验证的装饰器,我可以用来装饰路由器类中的方法(路由)列表。

所以我有一个带有几种方法的路由器,并尝试了这样的东西。但是,当我调用要装饰的路由时,装饰器没有附加。

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

如何解决此问题?

你有几个问题。

首先,我不认为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​

我认为您遇到了this上下文问题。

请记住,"胖箭头"=>在函数定义时绑定到this。因此,当您想将其绑定到MyApp实例时,您的decorateAuthenticatedFunctions: =>将绑定到全局this

试试这个:

...
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 
...