Coffeescript空白、参数和函数作用域
我用咖啡脚本已经有一段时间了。我发现它总体上是一种很好的语言,当然比普通的JS要好,但我发现它的缩进规则仍然让我感到困惑。举个例子:Coffeescript空白、参数和函数作用域,coffeescript,nested,indentation,Coffeescript,Nested,Indentation,我用咖啡脚本已经有一段时间了。我发现它总体上是一种很好的语言,当然比普通的JS要好,但我发现它的缩进规则仍然让我感到困惑。举个例子: Bacon.mergeAll( @searchButton.asEventStream('click') @searchInput.asEventStream('keyup') .filter (e) => e.keyCode is 13 ) .map => @searchInput.val() .flatMap
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'
(代码是基于,顺便说一句)但我花了大量的尝试和错误,使其正确
为什么mergeAll
和asEventStream
的参数周围需要括号?为什么缩进不足以确定参数列表的开始和结束位置?OTOH,为什么缩进对于map
和flatMapLatest
足够?为什么挂起方法之前的空格,例如.filter
(其缩进级别)不足以确定它绑定到什么?这似乎被完全忽视了
这种语言的缩进规则有明确的指南吗?我对Python语法一目了然,即使是非常复杂的嵌套,也从来没有遇到过问题,因此基于缩进的语法本身并不存在问题。CoffeeScript中的缩进通常定义块,而参数列表(不一定)是块。类似地,链式函数调用不是块;CoffeeScript只看到一行以
开头,并将其连接到类似或更低缩进的前一行
因此,asEventStream
需要括号,因为CoffeeScript会看到:
@searchInput.asEventStream 'keyup'.filter (e) => e.keyCode is 13
它将在'keyup'
字符串上调用filter
,并且该函数是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感到困惑,但请记住,你没有义务使用它。就像你不必总是避免括号一样;如果他们让事情变得更清楚,一定要用他们
如果代码更容易编写,阅读起来不那么模棱两可,维护起来也更简单,而不需要复杂的链接/语法(在本例中,所有这些似乎都是正确的),那么我建议跳过它
最后,CoffeeScript中的缩进语法组合可能使您或编译器绊倒。不过,大多数情况下,如果您查看某个内容,发现它很简单,编译器可能也会这么认为。如果您有疑问,编译器也可能有疑问,或者它会以意外的方式解释它。这是我所能提供的最好的“权威指南”(不知道有没有书面指南)。您看过这段代码生成的Javascript了吗?省略
()
时会发生什么
在尝试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(...);
省略()
给出错误,因为编译器无法知道mergeAll
是一个接受参数的函数。它没有理由期望出现缩进块
来自Python,我倾向于继续使用
(),[],{}
标记参数、数组和对象等结构,除非没有它们,代码更清晰。它们经常帮助我阅读代码,即使编译器不需要它们。Coffeescript在使用缩进表示代码块方面也类似于Python(与Javascript和其他C
样式化语言中使用的{}
相反)。仅仅因为可以使用匿名函数并不意味着必须这样做。如果你破坏了你的函数并给它们命名,那么你就可以用简单易读的东西,比如o.map(把它们弄乱)、filter(把垃圾过滤掉)。我只是想确保我理解语法的所有细微差别,以免落入陷阱。谢谢,这很有意义。CS确实将一条以点开始的线连接到“类似或更低缩进的前一行”,但并非所有内容都被视为块<代码>如果
,而
和函数定义是,而参数列表不是。关于fat arrow的使用=>
我在这里发布了一篇评论,如果你感兴趣的话:@Tobia Heh,好评论。就我个人而言,对于我经常编写的代码,胖箭头是一个“特例”。没有必要经常使用它来证明总是使用它是正确的。也就是说,我通常不需要一个绑定函数,所以当我需要绑定函数时,我喜欢显式地描述它。也就是说,你的论点并非毫无价值;如果我的项目不同,我会考虑的。
Bacon.mergeAll
@searchButton.asEventStream('click')
@searchInput.asEventStream('keyup')