Coffeescript. И снова о нём. Резюме о приятностях

CoffeeScript — это, если так можно выразиться, язык высокого уровня, преобразуемый в JavaScript.

Основан простым парнем по имени Jeremy Ashkenas при поддержке его корешей, которые упомянуты на github'е. Вдохновленный Ruby, паренёк решил упростить всем нам жизнь и создал его! CoffeeScript!



Цели



Целью и предназначением этого языка является устранение головной боли разработчика, использующего JavaScript. Всем, кто знаком с JavaScript, знают как трудно поддерживать быстро растущий код с множеством магии вроде наследования, передачи контекста объекта в callback методы и многое, многое другое. И те, у кого хватило нервов написать многостраничный native код с разбиением на классы, использующие естественное для JavaScript прототипированное наследование, могут с радостью застрелиться, так как то что они делали — это забивали гвозди тухлой рыбой :). Эй, чуваки, в CoffeeScript это делается легко и просто:

  1. class Animal
  2.   name: "animal"
  3.  
  4.   move: (meters) ->
  5.     alert(@name + " moved " + meters + "m.")
  6.  
  7. class Snake extends Animal
  8.   constructor: (name) ->
  9.     @name: name
  10.  
  11.   move: ->
  12.     alert("Slithering...")
  13.     super(5)
  14.  
  15. class Horse extends Animal
  16.   constructor: (name) ->
  17.     @name: name
  18.  
  19.   move: ->
  20.     alert("Galloping...")
  21.     super(45)
  22.  
  23. sam: new Snake("Sammy the Python")
  24. tom: new Horse("Tommy the Palomino")
  25.  
  26. sam.move()
  27. tom.move()


Мы даже можем не волноваться (до момента, когда надо будет что-то подебажить) о том какой CoffeeScript подписал контракт с всенижним, а всего лишь быть уверенными, что на выходе получим native'ный быстроработающий код:

  1. (function(){
  2.   var Animal, Horse, Snake, sam, tom;
  3.   var __extends = function(child, parent) {
  4.     var ctor = function(){ };
  5.     ctor.prototype = parent.prototype;
  6.     child.__superClass__ = parent.prototype;
  7.     child.prototype = new ctor();
  8.     child.prototype.constructor = child;
  9.   };
  10.   Animal = function() {};
  11.   Animal.prototype.move = function(meters) {
  12.     return alert(this.name + " moved " + meters + "m.");
  13.   };
  14.  
  15.   Snake = function(name) {
  16.     this.name = name;
  17.     return this;
  18.   };
  19.   __extends(Snake, Animal);
  20.   Snake.prototype.move = function() {
  21.     alert("Slithering...");
  22.     return Snake.__superClass__.move.call(this, 5);
  23.   };
  24.  
  25.   Horse = function(name) {
  26.     this.name = name;
  27.     return this;
  28.   };
  29.   __extends(Horse, Animal);
  30.   Horse.prototype.move = function() {
  31.     alert("Galloping...");
  32.     return Horse.__superClass__.move.call(this, 45);
  33.   };
  34.  
  35.   sam = new Snake("Sammy the Python");
  36.   tom = new Horse("Tommy the Palomino");
  37.   sam.move();
  38.   tom.move();
  39. })();


И не надо волноваться о конфликтах имен, так как все выполняется в своем окружении. Но если потребуется «расшарить» класс или переменную из такого «пакета», ничего же не стоит присвоить ссылку на них переменной в глобальном пространстве имен.

О документации.



Почитать на английском о том, как пользоваться CoffeeScript можно тут. На мой взгляд все доступно описано и с примерами.

Особенности.



Все coffee скрипты «варятся» в своей кофеварке, чтобы не «портить» другие coffee скрипты. Лично я считаю это правильным.

Короткая лямбда — это просто супер. А еще, что очень понравилось, так это передача контекста в callback обработчики:

  1. class Data
  2.   manyData: null
  3.  
  4.   constructor: ->
  5.     deferred: new Deferred()
  6.  
  7.     @initData(deferred)
  8.  
  9.     SomeClass.fillData(deferred)
  10.  
  11.   initData: (deferred) ->
  12.  
  13.       deferred.addCallback: (data) =>
  14.         @manyData: data
  15.  
  16.       deferred.addCallback: (error) ->
  17.         alert(error.name + ":" + error.message)
  18.  
  19. new Data()


На выходе:


  1. var Data;
  2. Data = function() {
  3.   var deferred;
  4.   deferred = new Deferred();
  5.   this.initData(deferred);
  6.   SomeClass.fillData(deferred);
  7.   return this;
  8. };
  9. Data.prototype.manyData = null;
  10. Data.prototype.initData = function(deferred) {
  11.   deferred.addCallback = (function(__this) {
  12.     var __func = function(data) {
  13.       this.manyData = data;
  14.       return this.manyData;
  15.     };
  16.     return (function() {
  17.       return __func.apply(__this, arguments);
  18.     });
  19.   })(this);
  20.   deferred.addCallback = function(error) {
  21.     return alert(error.name + ":" + error.message);
  22.   };
  23.   return deferred.addCallback;
  24. };
  25.  
  26. new Data();


Согласитесь, что код на coffee выглядит боллее адекватным.

Теперь не надо беспокоиться об объявлении переменных через var, а о слове function вообще забыть — они запрещены в CoffeeScript. Но если надо вставить обычный JavaScript в искодники CoffeeScript, просто оберните их в символы ` `:

  1. hi: `function() {
  2.   return [document.title, "Hello JavaScript"].join(": ");
  3. }`
  4.  
  5. `var getSomeValue = function() { ... }`


В результате:


  1. var hi;
  2. hi = function() {
  3.   return [document.title, "Hello JavaScript"].join(": ");
  4. };
  5. var getSomeValue = function() { ... };


Но это, думаю, может понадобиться только в крайних случаях отчаяния.

Фишки



В CoffeeScript имеется доступ к разного рода языковым конструкциям, к сожалению отсутсвующим в Native JavaScript, приведу несколько примеров, взятых с сайта проекта.

CoffeeScript


  1. cholesterol: 127
  2.  
  3. healthy: 200 > cholesterol > 60


JavaScript


  1. var cholesterol, healthy;
  2. cholesterol = 127;
  3. healthy = (200 > cholesterol) && (cholesterol > 60);


CoffeeScript


  1. theBait: 1000
  2. theSwitch:  0
  3.  
  4. [theBait, theSwitch]: [theSwitch, theBait]


JavaScript


  1. var _a, theBait, theSwitch;
  2. theBait = 1000;
  3. theSwitch =  0;
  4. _a = [theSwitch, theBait];
  5. theBait = _a[ 0];
  6. theSwitch = _a[1];


CoffeeScript


  1. numbers: [ 0 .. 9]
  2.  
  3. threeToSix: numbers[3..6]
  4.  
  5. copy: numbers[ 0...numbers.length]


JavaScript


  1. var copy, numbers, threeToSix;
  2. numbers = (function(){
  3.   a = [];for (var i =  0; ( 0 <= 9 ? i <= 9 : i >= 9); ( 0 <= 9 ? i += 1 : i -= 1)) a.push(i);
  4.   return a;
  5. }).call(this);
  6. threeToSix = numbers.slice(3, 6 + 1);
  7. copy = numbers.slice( 0, numbers.length);


CoffeeScript


  1. yearsOld: {max: 10, ida: 9, tim: 11}
  2.  
  3. ages: for child, age of yearsOld
  4.   child + " is " + age


JavaScript


  1. var _a, _b, age, ages, child, yearsOld;
  2. var __hasProp = Object.prototype.hasOwnProperty;
  3. yearsOld = {
  4.   max: 10,
  5.   ida: 9,
  6.   tim: 11
  7. };
  8. ages = (function() {
  9.   _a = []; _b = yearsOld;
  10.   for (child in _b) { if (__hasProp.call(_b, child)) {
  11.     age = _b[child];
  12.     _a.push(child + " is " + age);
  13.   }}
  14.   return _a;
  15. })();


CoffeeScript


  1. years: [2000 .. 2010]
  2.  
  3. for year in years
  4.   "year is " + year


JavaScript


  1. var _a, _b, _c, year, years;
  2. years = (function(){
  3.   a = [];for (var i = 2000; (2000 <= 2010 ? i <= 2010 : i >= 2010); (2000 <= 2010 ? i += 1 : i -= 1)) a.push(i);
  4.   return a;
  5. }).call(this);
  6. _b = years;
  7. for (_a =  0, _c = _b.length; _a < _c; _a++) {
  8.   year = _b[_a];
  9.   "year is " + year;
  10. }


Резюме



Для полноценной разработки, конечно, не хватает распространных плагинов подсветки и автодополнений, но если не учитывать этих временных трудностей, CoffeeScript по сути явно упрощает написание сложных JavaScript приложений.

Огромный плюс CoffeeScript — это то, что мы имеем возможность писать легко сложный код, который в runtime не требует подключения различных библиотек эмулирующих классические классы и те или иные реализации ecma стандартов, что каждый сможет согласится, значительно увеличит скорость работы скриптов.

А организацию режима разработки и deploy'я каждый выберет по вкусу, это задача не в этой теме.

Спасибо за внимание.
+24
2 июля 2010, 16:55
60
ich 3,5 G+

комментарии (56)

+3
null21 #
Исправьте первый линк, пожалуйста. А так, спасибо большое.
0
ich #
исправил линки
+2
chyc #
estupende!

только в сасаохамлообзазных штуках бывают с отладкой проблемы. Мол ошибка в строке 795 пойди её потом в 100 строчном кофейном исходнике найди.
+3
Terion #
ну на то и написано на сайте:
Disclaimer: Coffeescript is just for fun. Until it reaches 1.0, there are no guarantees that the syntax won't change between versions.
0
supercritical #
Latest Version: 1.0.1
+1
Terion #
то что он компилится в нативный код это очень круто (сделали бы такой компайлер для jQuery, эх...)
но какой-то у него синтаксис… странный…
ну, если я не ошибаюсь, он на рубиновский похож, так что не-рубинщикам будет трудно привыкнуть…
+3
ich #
я долго сопротивлялся Ruby синтаксису, мне и js'ный вполне нравится, но когда кода много, то глаза начинают проситься домой, так что пришлось переосилить, уверен не зря
0
tenshi #
я как-то юзал компилятор который код {a_b_c: a+b+c } разворачивал в function( a, b ,c ){ return a+b+c } но потом забил, ибо оно того не стоит х)
+1
ConstNW #
0
Terion #
хм… а чем его запускать? О_о
+1
ConstNW #
0
Terion #
спасибо, будем крутить..)
+1
tyaga #
Спасибо за статью.

Несмотря на то, что вы написали, что деплой — по вкусу, стоит, наверное, упомянуть, что серверный транслятор coffee-script для своей работы требует node.js (который, кажется, сложно поставить на винду), а клиентский компилятор работает только с inline-скриптами. Ну, многие же разрабатывают в винде ведь.
0
dieinzige #
ну они это, дальше писать свои сопли из джав-скрипта и кричать jQuery — круче всех
0
Alroniks #
да. с win проблемы. что касается разработки, то на работе стоит windows. ставить и настраивать ubuntu можно, но не приветствуется со стороны начальства, так как на работе главное выполнить поставленные задачи.

а по теме… народ то на винде деплоит, но ведь окончательный вариант все равно будет на сервере. если нужно использовать технологию, то и на машине нужно организовать максимально приближенную к реальности среду. для этого и денверы всякие были придуманы — с одной стороны — упростить настройку, с другой стороны предоставить почти такой же сервер, как и на хостинге (за исключением неимения прав доступа в винде). Так что это не первоочередная проблема.
–2
aubt #
> народ то на винде деплоит, но ведь окончательный вариант все равно будет на сервере
Вы в курсе что такое win server, iis? :)
0
tyaga #
А почему я написал серверный транслятор, но клиентский компилятор, одному Богу известно :-)
0
ConstNW #
почему проблема? node.js собрали под CygWin
0
tyaga #
Ну все отностительно. Кому и CygWin — запредельно по сравнению с Denwer :)
0
fuCtor #
Проблема не только под win, хотел собрать под FreeBSD 8.2 amd64 из портов. Не тут то было, выкидывает что сборка не поддерживается.
0
max7 #
А Я вот мечтаю о yield (во всех реализациях javascript).
+1
sunnybear #
что-то непонятно, зачем изучать еще один язык, если и так JS знаешь?
0
aspect #
>Целью и предназначением этого языка является устранение головной боли разработчика, использующего Javascript…
0
Kolyaj #
Я использую Javascript, у меня нет головной боли.
+2
tenshi #
чтобы «писать меньше и делать больше» %-)
+2
tenshi #
a = [];for (var i = 0; ( 0 <= 9? i <= 9: i >= 9); ( 0 <= 9? i += 1: i -= 1)) a.push(i);

магии много в этом языке я чувствую х)))
0
aspect #
видимо можно писать не только 0..9 но и 9..0, кодогенерация, она такая
0
tenshi #
ага, и на каждой итерации проверять а не стала ли девятка ВНЕЗАПНО меньше нуля х))
+1
aspect #
очевидная причина этого — переменная граница
[1..func(systime)]
–1
tenshi #
не выдумывай х)
+9
tenshi #
удачи тебе с отладкой, юный фанат «быстрого» языка х)))
0
ConstNW #
отладку прикрутят.
например такую же как в haxe: в дебаг версии ведется свой «стек» вызовов с привязкой к позиции в исходном файле.
0
tenshi #
ага, и пошаговую отладку прикрутят?
0
ConstNW #
для пошаговой отладки достаточно готовых js-решений.
но в перспективе почему бы и нет.
0
tenshi #
не достаточно, ибо в генерированном коде чёрт ногу сломит
0
ConstNW #
это вам с непривички так кажется.
0
Pilat #
Вопрос: для JS есть куча инструментария, например jslint. Есть ли что-то подобное для Coffeescript, или в больших проектах надо опечатки искать самостоятельно?
0
Manticore #
На офсайте написано, что «it compiles into clean Javascript (the good parts)… and passes through JSLint without warnings». Как я понимаю, jslint вызывается каждый раз при компиляции в js.
0
Pilat #
Ну после компиляции в JS вызывать jslint уже смысла нет. jslint (точнее его аналог для Coffeescript) нужен для анализа исходных текстов, а не откомпилированной версии. Интересно, какие ошибки ловит Coffeescript при компиляции?
0
knight #
Очень интересно, спасибо за статью.,
ИМХО грамотно использовать нативный синтаксис
0
MagaSoft #
все не могу понять эту страсть к кофе/хамл/сас. зачем учить новые синтаксисы и преумножать сущности? особенно в двух последних, которые по идее забота дизайнера/верстальщика.
0
stamir #
Сильно утрируя: «зачем учить всякие C и Pascal, когда есть ассемблер».
Вполне допускаю, что кому-то синтаксис Coffeescript будет удобнее, и что для их задач его будет достаточно.
0
Alexshl #
недавно был топик с минусами этого фреймворка здесь
0
Alexshl #
сократил ссылку т.к. почему-то глючит парсер ссылок

здесь bit.ly/bbrkiO
0
fzn7 #
Вот реально just for fun. Я не завидую JS программистам, которым через пару лет этой эйфории придется разбираться с таким кодом.
0
bolk #
Парсер «Хабры» поломал ссылки в тексте.
0
Guria #
Интересно приход NaCl с Python, Ruby и другими Mono спасёт любителей синтаксического сахара?
–4
Kolyaj #
>> Всем, кто знаком с Javascript, знают как трудно поддерживать быстро растущий код с множеством магии вроде наследования, передачи контекста объекта в callback методы и многое, многое другое.

Только на одном из проектов поддерживаю ~2 MB JS-кода, поддерживать не трудно. Может язык стоит изучить, перед тем, как такое говорить?
+2
ich #
Да, может вы и правы, и порядка 3х лет непосредственной практики маловато для того, чтобы знать язык. Но я так не считаю. Что касается вашего комментария, то я расцениваю его как дешевый понт о том кто круче, и к данной теме он отношения не имеет. Хотите помериться крутизной — вперед, но не в этот топик
–2
Kolyaj #
Вы считаете дешёвым понтом слова о том, что на Javascript без затруднений поддерживаются крупные проекты, если выбрать нормальную архитектуру приложения? Ну ладно, считайте.
+2
ich #
я даже пояснять не стану
0
piumosso #
Привет. К как с поддержкой eclipse и др.?
0
ich #
искал плагины, для eclipse и netbeans нет (надеюсь пока нет), есть плагин для IntelliJ IDEA, для TextMate, vim и еще что то, описано тут перед списком версий, в конце страницы
0
ich #
есть неплохой плагин подсветки для gedit тут, ну и элементарный фолдинг (this, return, имена переменных)
0
glazs #
Не дай бог придется поддерживать это в каком-либо проекте.
+1
Drinker #
Мне язык ОЧЕНЬ напоминает синтаксисом Erlang ;-) не знаю, как там с Руби (не в теме), но на эрланг похоже :)

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.