在咖啡脚本中构建类时,是否有理由不使用实例方法的粗箭头? [英] When building classes in coffeescript, is there ever a reason to not use the fat arrow for the instance methods?

查看:12
本文介绍了在咖啡脚本中构建类时,是否有理由不使用实例方法的粗箭头?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 coffeescript 中构建类时,是否有理由将粗箭头用于实例方法?

When building classes in coffeescript, is there ever a reason to not use the fat arrow for instance methods?

那好吧!很好的回复!:)
总结起来,问题是:
- 占用更多内存
- 无法修补
- 提出问题,为什么要使用这种方法?
约定:
- 绑定函数时要明确.
- 在构造函数中声明粗箭头方法.
- 尽可能多地使用,而不是在类声明中.

Ok then! Great reply! :)
To sum up, the problems are:
- Takes more memory
- Inability to patch
- Begs question, why is it used for this method?
Convention:
- Be explicit when binding functions.
- Declare fat arrowed methods in the constructor.
- Use as much as you want, just not in class declarations.

推荐答案

是的,有理由不总是使用粗箭头.事实上,我赞成 never 使用粗箭头方法:)

Yes, there are reasons to not use the fat arrows always. In fact i'd argue in favour of never using fat-arrowed methods :)

细箭头和粗箭头方法在概念上是不同的东西.前者编译成预期的基于原型的JS代码;这些方法属于类原型.另一方面,粗箭头方法与构造函数代码中的每个实例相关联.

Thin-arrow and fat-arrow methods are conceptually different things. The former are compiled to the expected prototype-based JS code; the methods belong to the class prototype. Fat-arrowed methods, on the other hand are associated with each instance in the constructor's code.

总是使用粗箭头方法最明显的缺点是它使每个类实例占用更多内存(因为它有更多自己的属性)并且它的初始化更慢(因为它必须创建那些绑定函数并设置它们每个创建实例的时间).

The most obvious disadvantage of always using fat-arrowed methods is that it makes each class instance take more memory (because it has more own properties) and its initialization be slower (because it has to create those bound functions and set them each time an instance is created).

使用粗箭头方法的另一个缺点是它打破了对方法的通常期望:方法不再是类实例之间共享的函数,但它现在是每个实例的单独函数.这可能会导致问题,例如,如果您想在类中定义方法后对其进行修改:

Another disadvantage of using fat-arrow methods is that it breaks the usual expectation of what a method is: a method is no longer a function shared between the instances of a class, but it now is a separate function for each instance. This can cause problems if, for example, you'd want to modify a method after it has been defined in the class:

class Foo
  # Using fat-arrow method
  bar: (x) => alert x

# I have some Foos
foos = (new Foo for i in [1..3])

# And i want to path the bar method to add some logging. 
# This might be in another module or file entirely.
oldbar = Foo::bar
Foo::bar = (args...) ->
  console.log "Foo::bar called with", args
  oldbar.apply @, args

# The console.log will never be called here because the bar method 
# has already been bound to each instance and was not modified by 
# the above's patch.
foo.bar(i) for foo, i in foos

<小时>

但在我看来,最重要的缺点更加主观:引入粗箭头方法会使代码(和语言)不必要地不一致且难以理解.


But the most important disadvantage in my opinion is more subjective: introducing fat-arrow methods makes the code (and the language) unnecessarily inconsistent and difficult to understand.

代码变得更加不一致,因为在引入胖箭头方法之前,任何时候我们在类定义中看到 <someProp>: <someVal> 我们知道这意味着声明一个名为 <someProp> 在类的原型中具有值 <someVal>"(除非 <someProp> == 'constructor',即一个特殊情况),如果 <someVal> 是一个数字或一个函数并不重要,它只是原型中的一个属性.随着粗箭头方法的引入,我们现在有了另一个不必要的特殊情况:如果 <someVal> 是一个粗箭头函数,它将与任何其他值完全不同.

The code becomes more inconsistent because before introducing fat-arrow methods any time we see <someProp>: <someVal> in a class definition we know it means "declare a property named <someProp> with a value <someVal> in the class' prototype" (unless <someProp> == 'constructor', which is a special case), it doesn't matter if <someVal> is a number or a function, it will just be a property in the prototype. With the introduction of fat-arrowed methods we now have another unnecessary special case: if <someVal> is a fat-arrowed function it will do a completely different thing than with any other value.

还有一个不一致的地方:胖箭头以不同的方式绑定this 在方法定义中使用时比在其他任何地方使用时.而不是保留外部 this(在 class 内部,this 绑定到类构造函数) this 粗箭头方法内部是定义方法时不存在的对象(即类的实例).

And there's another inconsistency: fat arrows bind the this differently when they are used in a method definition than when used anywhere else. Instead of preserving the outer this (which, inside a class, this is bound to the class constructor) the this inside a fat-arrowed method is an object that does not exist when the method is defined (i.e. an instance of the class).

如果你混合使用细箭头和粗箭头方法,代码也会变得更难理解,因为现在每次开发人员看到粗箭头方法时,他们都会问自己为什么需要它em> 方法被实例绑定.方法的声明和它的使用位置之间没有直接的关联,这就是需要使用胖箭头方法的地方.

If you mix thin-arrowed and fat-arrowed methods the code also becomes harder to follow because now every time a developer sees a fat-arrowed method they'll ask themselves why was it needed that for that method to be instance-bound. There's no immediate correlation between the method's declaration and where it's being used, which is where the need for fat-arrow method arises.

对于这一切,我建议永远不要使用粗箭头方法.更喜欢将方法绑定到将要使用它的实例,而不是声明方法的位置.例如:

For all this, i'd recommend to never use fat-arrow methods. Prefer binding the method to an instance where it's going to be used instead of where the method is declared. For example:

# Be explicit about 'onClick' being called on 'someObject':
$someJQueryElement.on 'click', (e) -> someObject.onClick e

# Instead of:
$someJQueryElement.on 'click', someObject.onClick

或者,如果您真的想在构造时为每个实例绑定方法,请明确说明:

Or, if you really want to bind the method on every instance on construction time, be explicit about that:

# Instead of fat-arrow methods:
class A
  constructor: ->
    @bar = 42
  foo: => 
    console.log @bar

# Assing the method in the constructor, just like you would 
# do with any other own property
class A
  constructor: ->
    @bar = 42
    @foo = => 
      console.log @bar

我认为在 class A 的第二个定义中,foo 方法所发生的事情比在第一个定义中更明确.

I think that in the second definition of class A it's much more explicit what is happening with the foo method than in the first definition.

最后,请注意,我根本不反对使用粗箭头.这是一个非常有用的结构,我一直将它用于正常功能;我只是更喜欢避免在 class 方法定义中使用它:)

Finally, notice that i'm not arguing against using the fat arrow at all. It's a very useful construct and i use it all the time for normal functions; i just prefer to avoid using it inside a class method definition :)

编辑:反对使用粗箭头方法的另一种情况:装饰器函数:

Edit: Another case against using fat-arrowed methods: decorator functions:

# A decorator function to profile another function.
profiled = (fn) ->
  (args...) ->
    console.profile()
    fn.apply @, args
    console.profileEnd()

class A
  bar: 10

  # This works as expected
  foo: profiled (baz) ->
    console.log "@bar + baz:", @bar + baz

  # This doesn't
  fatArrowedFoo: profiled (baz) =>
    console.log "@bar + baz:", @bar + baz

(new A).foo 5           # -> @bar + baz: 15
(new A).fatArrowedFoo 5 # -> @bar + baz: NaN

这篇关于在咖啡脚本中构建类时,是否有理由不使用实例方法的粗箭头?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆