CoffeeScript,何时在箭头(->)上使用FAT箭头(=>),反之亦然

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (12)

在CoffeeScript中构建类时,是否应该使用=>操作符和使用->接线员?

提问于
用户回答回答于

在定义方法时,找到的主要用例是,当想要使用方法作为回调时,该方法引用实例字段:

class A
  constructor: (@msg) ->
  thin: -> alert @msg
  fat:  => alert @msg

x = new A("yo")
x.thin() #alerts "yo"
x.fat()  #alerts "yo"

fn = (callback) -> callback()

fn(x.thin) #alerts "undefined"
fn(x.fat)  #alerts "yo"
fn(-> x.thin()) #alerts "yo"

正所看到的,如果不使用胖箭头,将实例的方法引用作为回调传递可能会遇到问题。将对象的实例绑定到this而瘦箭头没有,所以像上面这样被调用为回调的瘦箭头方法不能访问实例的字段,例如@msg或者调用其他实例方法。在最后一行中,对于使用过细箭头的情况,有一个解决办法。

用户回答回答于

在其他答案中没有提到的一点是,在没有必要的情况下,使用FAT箭头绑定函数可能会导致意外的结果,例如在这个例子中,我们只需要调用DummyClass。

class DummyClass
    constructor : () ->
    some_function : () ->
        return "some_function"

    other_function : () =>
        return "other_function"

dummy = new DummyClass()
dummy.some_function() == "some_function"     # true
dummy.other_function() == "other_function"   # true

在这种情况下,函数所做的事情完全符合人们的预期,而且使用FAT箭头似乎没有损失,但是在DummyClass原型已经定义之后(例如更改一些警告或更改日志的输出)时会发生什么:

DummyClass::some_function = ->
    return "some_new_function"

DummyClass::other_function = ->
    return "other_new_function"

dummy.some_function() == "some_new_function"   # true
dummy.other_function() == "other_new_function" # false
dummy.other_function() == "other_function"     # true

正如我们所看到的,重写我们先前定义的原型函数会导致_函数被正确覆盖但其他_函数在实例上保持不变,就像FAT箭头导致其他_函数从类绑定到所有实例,这样实例就不会引用它们的类来查找函数。

DummyClass::other_function = =>
    return "new_other_new_function"

dummy.other_function() == "new_other_new_function"    # false

second_dummy = new DummyClass()
second_dummy.other_function() == "new_other_new_function"   # true

即使是FAT箭头也不会像FAT箭头那样工作,只会导致函数绑定到新实例(这确实像人们所期望的那样获得了新的功能)。

然而,这会导致一些问题,如果我们需要一个函数(例如,在将日志函数切换到输出框或其他什么情况下),它将在所有现有实例(包括事件处理程序)上工作,怎么办?因此,我们不能在原始定义中使用胖箭头但是,我们仍然需要访问事件处理程序中的内部属性。我们使用脂肪箭而不是细箭的确切原因。

实现这一点的最简单方法是在原始类定义中只包含两个函数,一个函数用细箭头定义,它执行您希望执行的操作,另一个函数定义为FAT箭头,只调用第一个函数,例如:

class SomeClass
    constructor : () ->
        @data = 0
    _do_something : () ->
        return @data
    do_something : () =>
        @_do_something()

something = new SomeClass()
something.do_something() == 0     # true
event_handler = something.do_something
event_handler() == 0              # true

SomeClass::_do_something = -> return @data + 1

something.do_something() == 1     # true
event_handler() == 1              # true

因此,何时使用细箭头可以很容易地用以下四种方法来总结:

  1. 当这两种条件都是Mett时,应该单独使用细箭头函数:
- The method will never be passed by reference including event\_handlers e.g. you never have a case such as: some\_reference = some\_instance.some\_method; some\_reference()
- AND the method should be universal over all instances so if the prototype function changes so does the method over all instances

  1. 在满足以下条件时,应单独使用FAT箭头函数:
- The method should be bound precisely to the instance at instance creation and remain permanently bound even if the function definition changes for the prototype, this includes all cases where the function should be an event handler and the event handler behaviour should be consistent

  1. 在满足以下条件时,应该使用FAT箭头函数,该函数直接调用细箭头函数:
- The method is required to be called by reference such as an event handler
- AND the functionality may change in future affecting existing instances by replacing the thin arrow function

  1. 当满足以下条件时,应该使用直接调用FAT箭头(未演示)函数的细箭头函数:
- The fat arrow function must be always attached to the instance
- BUT the thin arrow function may change (even to a new function which doesn't use the original fat arrow function)
- AND the thin arrow function is never needed to be passed by reference

在所有的方法中,都必须考虑到原型函数是否可能被改变,例如,对于特定实例的行为是否正确--例如,尽管函数是用胖箭头定义的,但如果它调用在原型中更改的方法,则它的行为在实例中可能不一致。

扫码关注云+社区