在CoffeeScript中构建类时,是否应使用=>
(“胖箭头”)运算符定义所有实例方法,并使用->
运算符定义所有静态方法?
答案 0 :(得分:152)
不,这不是我会使用的规则。
我在定义方法时找到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"
如您所见,如果您不使用fat-arrow,则可能会遇到将实例方法的引用作为回调传递的问题。这是因为胖箭头将对象的实例绑定到this
而瘦箭头没有绑定,因此上面称为回调的瘦箭头方法无法访问实例的字段,如{{1}或调用其他实例方法。最后一行是针对使用细箭头的情况的解决方法。
答案 1 :(得分:13)
在其他答案中没有提到的一点需要注意的是,在没有必要的情况下使用胖箭头绑定函数会导致意想不到的结果,例如在本例中我们只调用DummyClass。< / p>
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
在这种情况下,函数完全按照人们的预期运行,并且似乎没有使用胖箭头的损失,但是当我们在已定义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
正如我们所看到的那样,覆盖我们先前定义的原型函数会导致some_function被正确覆盖,但是其他函数在实例上保持不变,因为胖箭头导致类中的other_function绑定到所有实例,因此实例赢了“t = t回到他们的班级找到一个函数
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
即使胖箭也不会工作,因为胖箭只会导致函数绑定到新实例(它确实获得了新功能)。
然而,这会导致一些问题,如果我们需要一个函数(例如,在将日志记录功能切换到输出框或其他东西的情况下),它将适用于所有现有实例(包括事件处理程序)[因此我们可以& #39;在原始定义中使用胖箭头]但我们仍然需要访问事件处理程序中的内部属性[我们使用胖箭头而不是细箭头的确切原因]。
完成此操作的最简单方法是在原始类定义中仅包含两个函数,一个用精简箭头定义,执行您希望执行的操作,另一个定义为胖箭头除了调用之外什么都不做第一个函数,例如:
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
因此,当使用瘦/脂箭时,可以通过四种方式总结起来:
当满足两个条件时,应使用单箭头功能:
满足以下条件时,应使用Fat arrow单独函数:
满足以下条件时,应使用直接调用细箭头函数的胖箭头函数:
当满足以下条件时,应使用直接调用胖箭头(未演示)函数的细箭头函数:
在所有方法中,必须考虑原型函数可能被更改的情况,无论特定实例的行为是否正常行为,例如,虽然使用胖箭头定义函数,但其行为在实例中可能不一致如果它调用原型
中更改的方法答案 2 :(得分:9)
通常,->
没问题。
class Foo
@static: -> this
instance: -> this
alert Foo.static() == Foo # true
obj = new Foo()
alert obj.instance() == obj # true
注意静态方法如何返回this
的类对象,实例返回this
的实例对象。
发生的事情是调用语法提供this
的值。在这段代码中:
foo.bar()
默认情况下, foo
将成为bar()
函数的上下文。所以它只是按你想要的方式工作。当您以不使用点语法进行调用的其他方式调用这些函数时,您只需要胖箭头。
# 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()
在这两种情况下,使用胖箭头声明该功能将允许这些功能。但除非你做的事情很奇怪,否则你通常不需要。
因此,在真正需要->
之前使用=>
,默认情况下不要使用=>
。
答案 3 :(得分:5)
只是一个没有出现胖箭的例子
不起作用:(@ scanvas undefined)
class Test
constructor: ->
@canvas = document.createElement 'canvas'
window.addEventListener 'resize', ->
@canvas.width = window.innerWidth
@canvas.height = window.innerHeight
工作:( @canvas定义)
class Test
constructor: ->
@canvas = document.createElement 'canvas'
window.addEventListener 'resize', =>
@canvas.width = window.innerWidth
@canvas.height = window.innerHeight