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

Ali*_*ehi 131 coffeescript arrow-functions

在CoffeeScript中构建类时,是否应使用=>("胖箭头")运算符定义所有实例方法,并使用->运算符定义所有静态方法?

nic*_*ten 154

不,这不是我会使用的规则.

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

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"
Run Code Online (Sandbox Code Playgroud)

如您所见,如果不使用fat-arrow,则可能会遇到将实例方法的引用作为回调传递的问题.这是因为fat-arrow将对象的实例绑定到this而瘦箭不绑定,因此如上所述称为回调的瘦箭方法无法访问实例的字段@msg或调用其他实例方法.最后一行是针对使用细箭头的情况的解决方法.

  • 当你想使用从细箭头调用的`this`时,你会怎么做,还有你用胖箭头得到的实例变量? (2认同)

Jam*_*tor 13

其他答案中没有提到的一点需要注意的是,在没有必要的情况下使用胖箭头绑定函数会导致意外的结果,例如在本例中我们只调用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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,函数完全按照人们的预期运行,并且似乎没有使用胖箭头的损失,但是当我们在已经定义DummyClass原型之后修改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
Run Code Online (Sandbox Code Playgroud)

我们可以看到覆盖我们之前定义的原型函数会导致some_function被正确覆盖,但是其他函数在实例上保持不变,因为胖箭头导致类中的other_function绑定到所有实例,因此实例不会引用它们的类找到一个功能

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
Run Code Online (Sandbox Code Playgroud)

即使胖箭也不会工作,因为胖箭只会导致函数绑定到新实例(它确实获得了新功能).

然而,这导致了一些问题,如果我们需要什么样的功能(例如,在切换日志记录功能,输出箱或某事的情况下),将在现有的所有实例(包括事件处理程序)工作[因为如此,我们不能用原始定义中的胖箭头]但我们仍然需要访问事件处理程序中的内部属性[我们使用胖箭头而不是细箭头的确切原因].

那么做到这一点最简单的方法是仅仅包括在原来的类定义两个功能,一个用细箭头这确实是要执行的操作定义,并与脂肪箭头,什么也不做的另一个定义,但调用的第一个函数例如:

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
Run Code Online (Sandbox Code Playgroud)

因此,当使用瘦/脂箭时,可以通过以下四种方式总结起来:

  1. 当两个条件都满足时,应该使用单箭头功能:

    • 该方法永远不会通过引用传递,包括event_handlers,例如,你永远不会遇到如下情况:some_reference = some_instance.some_method; some_reference()
    • 并且该方法应该在所有实例上是通用的,因此如果原型函数发生更改,则所有实例的方法都会更改
  2. 满足以下条件时,应使用Fat arrow单独函数:

    • 该方法应该在实例创建时精确绑定到实例,并保持永久绑定,即使函数定义更改为原型,这包括函数应该是事件处理程序并且事件处理程序行为应该是一致的所有情况
  3. 当满足以下条件时,应使用直接调用细箭头函数的胖箭头函数:

    • 该方法需要通过引用调用,例如事件处理程序
    • 并且通过替换细箭头功能,功能可能在将来影响现有实例
  4. 当满足以下条件时,应使用直接调用胖箭头(未演示)函数的细箭头函数:

    • 胖箭头函数必须始终附加到实例
    • 但是细箭头功能可能会改变(即使是不使用原始胖箭头功能的新功能)
    • 并且永远不需要通过引用传递细箭头函数

在所有这些方法,必须在原型的功能可能会被更改为特定情况下的行为是否会正确的行为,例如虽然功能与肥胖定义箭头其行为的一个实例内可能不一致如果它调用的情况下,可以考虑在原型中更改的方法


Ale*_*yne 9

通常,->很好.

class Foo
  @static:  -> this
  instance: -> this

alert Foo.static() == Foo # true

obj = new Foo()
alert obj.instance() == obj # true
Run Code Online (Sandbox Code Playgroud)

注意静态方法如何返回类对象,this实例返回实例对象this.

发生的事情是调用语法提供的值this.在这段代码中:

foo.bar()
Run Code Online (Sandbox Code Playgroud)

foobar()默认情况下将是该函数的上下文.所以它只是按你想要的方式工作.当您以不使用点语法进行调用的其他方式调用这些函数时,您只需要胖箭头.

# Pass in a function reference to be called later
# Then later, its called without the dot syntax, causing `this` to be lost
setTimeout foo.bar, 1000

# Breaking off a function reference will lose it's `this` too.
fn = foo.bar
fn()
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,使用胖箭头声明该功能将允许这些功能.但除非你做一些奇怪的事情,否则你通常不需要.

所以->直到你确实需要=>使用=>,默认情况下永远不要使用.

  • 当然会,但这将属于"做错了".我现在编辑了我的答案并解释了在类的静态/实例方法上需要`=>`的时候. (2认同)

use*_*501 5

只是一个没有胖箭头的例子

不起作用:(@ scanvas undefined)

class Test
  constructor: ->
    @canvas = document.createElement 'canvas'
    window.addEventListener 'resize', ->
      @canvas.width = window.innerWidth
      @canvas.height = window.innerHeight
Run Code Online (Sandbox Code Playgroud)

作品:( @canvas定义)

class Test
  constructor: ->
    @canvas = document.createElement 'canvas'
    window.addEventListener 'resize', =>
      @canvas.width = window.innerWidth
      @canvas.height = window.innerHeight
Run Code Online (Sandbox Code Playgroud)