我一直在使用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,顺便说一句),但为了做到这一点,我花了很多的试验和错误。
为什么mergeAll
和asEventStream
需要围绕他们的参数括号?为什么缩进不足以确定其参数列表的开始和结束位置? OTOH,为什么缩进到map
和flatMapLatest
?为什么挂起方法之前的空格,例如.filter
(它的缩进级别)不足以确定它绑定到什么?它似乎完全被忽略了。
这种语言的缩进规则是否有确切的指南?即使使用非常复杂的嵌套,我也从来没有理解Python语法的问题,所以这不是基于缩进的语法本身的问题。
答案 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
)。