Coffeescript空白,参数和功能范围

时间:2013-12-08 12:36:30

标签: coffeescript nested indentation

我一直在使用CoffeeScript。我发现它总体来说是一个很好的语言,当然比普通的JS更好,但我发现我仍然对它的缩进规则感到困惑。举个例子:

Bacon.mergeAll(
    @searchButton.asEventStream('click')
    @searchInput.asEventStream('keyup')
        .filter (e) => e.keyCode is 13
)
.map =>
    @searchInput.val()
.flatMapLatest (query) =>
    Bacon.fromPromise $.ajax
        url: @searchURL + encodeURI query
        dataType: 'jsonp'

This does what it should(代码基于this tutorial,顺便说一句),但为了做到这一点,我花了很多的试验和错误。

为什么mergeAllasEventStream需要围绕他们的参数括号?为什么缩进不足以确定其参数列表的开始和结束位置? OTOH,为什么缩进到mapflatMapLatest?为什么挂起方法之前的空格,例如.filter(它的缩进级别)不足以确定它绑定到什么?它似乎完全被忽略了。

这种语言的缩进规则是否有确切的指南?即使使用非常复杂的嵌套,我也从来没有理解Python语法的问题,所以这不是基于缩进的语法本身的问题。

2 个答案:

答案 0 :(得分:1)

CoffeeScript中的缩进通常定义块,而参数列表不是(必然)块。类似地,链式函数调用不是块; CoffeeScript只是看到一行以.开头,并将其连接到上一行相似或较低的缩进。

因此,asEventStream需要括号,因为CoffeeScript会看到:

 @searchInput.asEventStream 'keyup'.filter (e) => e.keyCode is 13

哪个会在filter字符串上调用'keyup',并且该函数是filter的参数还是@searchInput.asEventStream('keyup'.filter)()的参数仍然不明确。最后一点显然没有多大意义,但CoffeeScript不是静态分析器,所以它不知道。

同时,一个函数一个块,因此.map()的函数参数在没有括号的情况下工作,因为它的缩进明确区分了它。即函数后面的行有较少的缩进。

就个人而言,我可能会写

Bacon.mergeAll(
  @searchButton.asEventStream('click'), # explicit comma
  @searchInput.asEventStream('keyup').filter (e) -> e.keyCode is 13 # no need for =>
)
.map(=> @searchInput.val()) # maybe not as pretty, but clearer
.flatMapLatest (query) =>
  Bacon.fromPromise $.ajax
    url: @searchURL + encodeURI query
    dataType: 'jsonp'

事实上,我可能会将其分解为单独的表达式,以使其更清晰。坚持语法糖,同时链接东西可以确实在CoffeeScript中混淆,但记住你没有义务使用它。同样,你没有义务总是避免括号;如果他们让事情更清楚,请务必使用'em!

如果代码更容易编写,读取更不明确,并且没有复杂的链接/语法就更容易维护(这个例子似乎都是如此),那么我只想跳过它。

最后,CoffeeScript中只有缩进语法的组合可以使您或编译器跳转。但是,大多数情况下,如果你看一些东西,并且发现它很简单,编译器可能也会这么认为。如果您有疑问,编译器可能也是如此,或者它会以意想不到的方式解释它。这是我在“权威指南”方面所能提供的最好的(不知道书面指南)。

答案 1 :(得分:1)

你看过这段代码生成的Javascript了吗?省略()时会发生什么。

Try Coffeescript我发现:

 @searchButton.asEventStream 'click'

没问题。第二个asEventStream编译为:

this.searchInput.asEventStream('keyup').filter(function(e) {

但省略()会将其更改为:

this.searchInput.asEventStream('keyup'.filter(function(e) {

filter现在是'keyup'的属性。将空格分隔为asEventStream('keyup')可以做同样的事情。

@searchInput.asEventStream ('keyup')

正如书面.mergeAll()所产生:

Bacon.mergeAll(...).map(...).flatMapLatest(...);

省略()

Bacon.mergeAll
    @searchButton.asEventStream('click') 
    @searchInput.asEventStream('keyup')

给出错误,因为编译器无法知道mergeAll是一个带参数的函数。它没有理由期望缩进块。

来自Python,我倾向于继续使用(),[],{}来标记参数,数组和对象等结构,除非代码在没有它们的情况下更清晰。他们经常帮助我阅读代码,即使编译器不需要它们。 Coffeescript也像Python一样使用缩进来表示代码块(而不是Javascript和其他{}样式语言中使用的C)。