Sim*_*olm 12 memory-management coffeescript arrow-functions
在coffeescript中构建类时,是否有理由不使用胖箭头方法?
编辑:那好吧!很好的回复!:)
总而言之,问题是:
- 需要更多内存
- 无法修补
- 请问问题,为什么它用于此方法?
惯例:
- 绑定功能时要明确.
- 在构造函数中声明胖箭头方法.
- 尽可能多地使用,而不是在类声明中.
epi*_*ian 18
是的,总有理由不使用胖箭.事实上,我赞成永远不要使用胖箭的方法:)
细箭和胖箭方法在概念上是不同的.前者被编译为预期的基于原型的JS代码; 这些方法属于类原型.另一方面,胖箭头方法与构造函数代码中的每个实例相关联.
始终使用胖箭头方法最明显的缺点是,它使每一个类的实例需要更多的内存(因为它有更多自己的属性)和它的初始化是比较慢(因为它创建这些约束的功能,每一次设置它们的实例被建造).
使用胖箭头方法的另一个缺点是,它打破了一个什么样的方法是普通的期望:一种方法是不再是一个类的实例之间共享的功能,但它现在是为每个实例单独的函数.例如,如果您想在类中定义方法后修改方法,则会导致问题:
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
Run Code Online (Sandbox Code Playgroud)
但是我认为最重要的缺点是更主观:引入胖箭头方法会使代码(和语言)不必要地不一致并且难以理解.
代码变得更加不一致,因为在引入fat-arrow方法之前,我们<someProp>: <someVal>在类定义中看到它们意味着"声明一个以类'原型中<someProp>的值命名的属性<someVal>"(除非<someProp> == 'constructor',这是一个特殊情况),它不会无论<someVal>是数字还是函数,它都只是原型中的属性.随着胖箭方法的引入,我们现在有了另一个不必要的特殊情况:如果<someVal>是一个胖箭头函数,它将完成与任何其他值完全不同的事情.
还有另一个不一致之处:胖箭头在方法定义中使用时的绑定方式与在this其他任何地方使用时绑定的方式不同.代替保持外的this(其内的class,this结合于类构造函数)的this一个脂肪箭头方法内是当该方法被定义(即一个类的实例),其不存在的对象.
如果你混合使用精简箭头和胖箭头的方法,代码也变得更难以遵循,因为现在每次开发人员看到一个胖箭头的方法时,他们会问自己为什么需要该方法实例绑定.方法的声明与其使用位置之间没有直接关联,这是需要fat-arrow方法的地方.
尽管如此,我建议永远不要使用胖箭方法.首选将方法绑定到将要使用它的实例,而不是声明方法的位置.例如:
# Be explicit about 'onClick' being called on 'someObject':
$someJQueryElement.on 'click', (e) -> someObject.onClick e
# Instead of:
$someJQueryElement.on 'click', someObject.onClick
Run Code Online (Sandbox Code Playgroud)
或者,如果您真的想在构造时绑定每个实例上的方法,请明确说明:
# 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
Run Code Online (Sandbox Code Playgroud)
我认为在class A它的第二个定义中,该foo方法发生的事情要比第一个定义更明确.
最后,请注意我并不反对使用胖箭.这是一个非常有用的结构,我一直用它来进行正常的功能; 我只是想避免在class方法定义中使用它:)
编辑:另一个反对使用胖箭头方法的案例:装饰函数:
# 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
Run Code Online (Sandbox Code Playgroud)
Tob*_*bia 12
让我添加我的替代视图.
@epidemian表达的避免胖箭的精心理由很好,但请考虑以下因素:
那么我建议总是使用胖箭作为一种习惯,无论是方法还是匿名函数.
这将使您的CoffeeScript代码更简单,更安全,更直观,因为您将了解this并@始终引用您正在定义其方法的当前对象,就像在大多数其他编程语言中一样,无论谁将在运行时调用您的函数和方法.
更正式地说,胖箭头使this关键字(和它的简写@)完全具有词法范围,就像任何其他标识符一样.编程语言历史表明,词法范围是最直观且不易出错的范围标识符的方式.这就是为什么它成为很久以前所有新语言的标准行为.
如果选择此路径,则精简箭头将成为例外,并且是一个有用的箭头.您将使用它来准备那些需要this引用调用者在运行时定义的内容而不是您自己的对象的特定回调.这是一种反直觉的含义this,但是一些JS库在用户提供的函数中需要这种行为.然后,细箭头将突出显示这些代码片段.如果我没记错的话,jQuery通常会在函数参数中提供你需要的所有内容,所以你可以忽略它的人工this,但其他库并不是仁慈的.
注意:CoffeeScript 1.6.1有一个与胖箭头方法相关的错误,所以你应该避免这种情况.以前版本和更高版本应该没问题.
当用作常规(匿名)函数时,胖箭头不会增加任何开销.在方法声明中,它确实增加了一个微小的 RAM和CPU开销(非常小:每个方法调用几纳秒和几个字节的RAM,后者在尾调用优化的引擎上消失.)
恕我直言,语言清晰度和安全性脂肪箭交换是足以容忍甚至欢迎小开销的理由.许多其他CoffeeScript习语为生成的代码(for循环等)添加了自己的微小开销,目的是使语言行为更加一致并且不易出错.胖箭没有什么不同.
| 归档时间: |
|
| 查看次数: |
1670 次 |
| 最近记录: |