【问题标题】:How to access arguments.callee in CoffeeScript class?如何访问 CoffeeScript 类中的 arguments.callee?
【发布时间】:2012-12-16 10:51:30
【问题描述】:

我有以下代码

class Foo 

  a: ->
    console.log arguments.callee.name

  b: ->
    @a()

  c: ->
    @a()


f = new Foo
f.b() #=> should output 'b'
f.c() #=> should output 'c'

问题:如何在我的类中获取调用函数的名称?


这是一个用例

class Something extends Stream

  foo: ->
    _helper 'foo', 'a', 'b', 'c'

  bar: ->
    _helper 'bar', 'my neighbor totoro'

  dim: ->
    _helper 'dim', 1, 2, 3

  sum: ->
    _helper 'sum', 'hello', 'world'

  _helper: (command, params...) ->
    @emit 'data', command, params...

something = new Something
something.foo()
something.bar()
# ...

我不想重复将每次调用的方法名称发送到我的私有 _helper 方法

【问题讨论】:

  • 你有充分的理由吗? arguments.callee 通常应该避免使用,不能在严格的代码中使用,我相信 CoffeeScript 默认使用。
  • @minitech、bc 将是可公开访问的包装方法,由 a 作为参数传递给我的另一段代码。这将有助于防止大量重复。
  • @naomik - 你能给我们提供abc 的代码吗?您无法访问 arguments.callee,但我们或许可以提出解决方法。
  • 这会毁了你的表现,仅供参考。 arguments 将所有现代 VM 踢入解释模式,而不是 JIT 编译为机器代码。
  • @Domenic,所以你建议只实现我在用例中的内容(第二个代码粘贴)?

标签: javascript node.js coffeescript


【解决方案1】:

所以要明确一点,我认为你拥有它的第二种方式是完全合理的,并且是要走的路。

但要回答您的问题,您可以动态生成每个函数以避免重新键入命令。

class Foo
  commands =
    foo: ['a', 'b', 'c']
    bar: ['my neighbor totoro']
    dim: [1,2,3]

  for own name, args of commands
    Foo::[name] = ->
      @emit 'data', name, args...

假设你希望函数有用,你仍然可以使用函数。

// ...
  commands =
    foo: (args...) -> return ['a', 'b', 'c']
    // ...

  for own name, cb of commands
    Foo::[name] = (command_args...) ->
      args = cb.apply @, command_args
      @emit 'data', name, args...

【讨论】:

    【解决方案2】:

    这就是我会做的:

    class Something extends Stream
        constructor: ->
            @foo = helper.bind @, "foo", "a", "b", "c"
            @bar = helper.bind @, "bar", "my neighbor totoro"
            @dim = helper.bind @, "dim", 1, 2, 3
            @sum = helper.bind @, "sum", "hello", "world"
    
        helper = (command, params...) ->
            @emit 'data', command, params...
    

    这种方法的优点是:

    1. helper 函数是一个私有变量。无法通过实例直接访问。
    2. helper 函数只声明一次,并在所有实例之间共享。
    3. 函数foobardimsumpartial applicationshelper。因此它们不会为函数体消耗更多内存。
    4. 它不需要像@loganfsmyth 的答案那样的循环。
    5. 更干净了。

    编辑:更简洁的方法是:

    class Something extends Stream
        constructor: ->
            @foo = @emit.bind @, "data", "foo", "a", "b", "c"
            @bar = @emit.bind @, "data", "bar", "my neighbor totoro"
            @dim = @emit.bind @, "data", "dim", 1, 2, 3
            @sum = @emit.bind @, "data", "sum", "hello", "world"
    

    当然,这有点多余,但您不能对 JavaScript 这样的语言有更多期望。这不是Factor。然而,它是可读的、干净的、易于理解的,而且最重要的是 - 正确。

    【讨论】:

    • 我不同意。您确实需要在实例化期间进行绑定,因为@ 在定义类时指向构造函数而不是构造函数的实例。你的 line converts to Something.prototype.foo = Something.emit.bind(Something, "data", "foo", "a", "b", "c") 这是错误的。 emit 方法在 Something 上不存在。我的line correctly converts to this.foo = this.emit.bind(this, "data", "foo", "a", "b", "c") 其中this 指向Something 的实例。请参阅class 文档。
    • 噢,是的,对不起,我显然没有充分考虑到这一点。删除我的评论。
    • "辅助函数只声明一次,并在所有实例之间共享。"这是错误的。不仅helper,还有foo等,现在都是实例成员,而不是原型成员。这意味着每次调用构造函数时都会重新创建它们,并且每次都会为它们分配新的内存。
    • @Domenic - helper 函数既不是实例成员也不是原型成员。它是在构造函数范围之外声明的私有变量。因此,无论实例数量如何,都只有一个 helper 函数。在函数定义时定义:tinyurl.com/ccouhkg
    • @Domenic - 其他函数foobardimsumhelper 的部分应用。是的,该类的每个实例都有自己的函数版本。不,函数不会每次都重新创建 - 内存仅分配给 this 指针和部分应用于 helper 函数的参数。没有创建一个全新的功能。这就是我提到“因此它们不会为函数体消耗更多内存”的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多