2013-12-08 4 views
0

Я использовал CoffeeScript некоторое время. Я считаю, что это хороший язык в целом, конечно, лучше, чем простой JS, но я считаю, что я все еще сбитый с толку его правилами отступов. Возьмем такой пример:Пробелы, аргументы и функции Coffeescript

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

Просто потому, что вы можете использовать анонимные функции, это не значит, что вам нужно. Если вы нарушите свои функции и дадите им имена, вы можете превратить путаницу в умственный разбор и догадки с помощью простых и читаемых вещей, таких как 'o.map (mangle_them) .filter (out_the_garbage) ...' –

+0

Да, я бы обязательно сделайте это в производственном коде. Я просто убедился, что понимаю все нюансы синтаксиса, чтобы я не попал в какую-то ловушку. – Tobia

ответ

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, но помните, что вы не обязаны его использовать. То же, что вы не обязаны всегда избегать круглых скобок; если они прояснят вещи, обязательно используйте их!

Если код легче писать, менее двусмысленным для чтения и проще поддерживать без сложного цепочки/синтаксиса (все это кажется верным для этого примера), то я бы сказал, просто пропустите его.

В конце есть только комбинации синтаксиса отступов в CoffeeScript, которые могут сделать либо вы, либо компилятор. В основном, однако, если вы посмотрите на что-то и найдете это прямолинейно, компилятор, вероятно, тоже так думает. Если вы сомневаетесь, компилятор может быть слишком, или он будет интерпретировать его неожиданными способами. Это лучшее, что я могу предложить в терминах «окончательного руководства» (не знаю письменного).

+0

Спасибо, это имеет смысл. CS действительно соединяет строку, начинающуюся с точки «до предыдущей строки с аналогичным или нижним отступом», за исключением того, что не все считается блоком. 'if',' while' и определение функции, а список параметров - нет. – Tobia

+0

Интересно, что определение объекта также является блоком: http://goo.gl/iyDtuL – Tobia

+0

Что касается использования толстой стрелки '=>' Я написал здесь набросок, если вам интересно: http: // stackoverflow.com/questions/13682986/when-building-classes-in-coffeescript-is-there-ever-a-reason-to-not-use-the-fat/17431824#17431824 – Tobia

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 языках).

Смежные вопросы