Пользователь
0,0
рейтинг
7 мая 2013 в 19:18

Разработка → Знакомство с CoffeeScript tutorial

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

CoffeeScript — это маленький язык, который транслируется в JavaScript. Его документация умещается на одной странице — coffeescript.org и отличается компактностью и наглядностью. Я даже сомневался в необходимости данной статьи, когда есть такое классное описание «от производителя», но все же рискнул расставить акценты и прояснить некоторые детали.

Введение


Если копнуть немного истории, то с 2009-го года язык писался на Ruby, с 2010 — он пишется на самом же CoffeeScript.
И в Ruby on Rails, начиная с версии 3.1, он «заменил» JavaScript.

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

JavaScript (читай ECMAScript), конечно, тоже не стоит на месте, развивается. В том числе перенимая некоторые идеи из CoffeeScript. Но если говорить про кросс-браузерный JavaScript, то лично у меня большие подозрения, что светлое будущее с продвинутым JavaScript наступит скоро. А CoffeeScript уже сейчас позволяет наслаждаться плодами технологического прогресса.

В этом ключе нельзя не упомянуть TypeScript, в определенном смысле, конкурента CoffeeScript. Он позиционируется, как надмножество JavaScript, добавляя новые фичи в язык, во многом отражая будущее JavaScript. С этой позиции он интереснее.
Но у CoffeeScript, есть преимущество, что ему не нужно сохранять совместимость с JavaScript, что, по-моему, дает больше свободы и позволяет сделать язык более выразительным. Так что, как минимум одна заслуживающая внимания альтернатива CoffeeScript есть. Но вернемся к теме.

Трансляция кода


Хорошо, как пользоваться этим вашим CoffeeScript?
Удобнее всего, на мой взгляд, работать с ним, как с модулем node.js. Ставится он проще простого:
npm install -g coffee-script

Создаем две папки, для определенности назовем их lib и src.
Создаем файл src/helloWorld.coffee и напишем, что нибудь на CoffeeScript. Например:
console.log('Hello world')

После этого запускаем транслятор:
coffee --compile --output lib/ src/
В итоге в папке lib будет лежать файл helloWorld.js, готовый к выполнению.
Конечно, на каждый чих запускать транслятор не интересно. Запуск команды
coffee -o lib/ -cw src/
заставляет следить за всеми изменениями файлов в папке src и самостоятельно транслировать их в JavaScript-код.

Синтаксис


Функции

Перейдем к самому языку. Напишем простенький код на CoffeeScript:
square = (x) -> x * x
cube   = (x) -> square(x) * x

Его JavaScript-эквивалент:
(function() {
	
var cube, square;

square = function(x) {
  return x * x;
};

cube = function(x) {
  return square(x) * x;
};

}).call(this);

Здесь мы создаем две функции, вычисляющие квадрат и куб числа соответственно.

Первым делом обратим внимание, что весь код спрятан внутри анонимной функции, которую мы сразу же вызываем.
Этот прием позволяет прятать все локальные переменные внутри функции, не заботясь о том, что они будут засорять глобальную область видимости. Ниже в статье мы будем опускать эту функцию для наглядности.

Далее обратим внимание, что объявления всех локальных переменных var cube, square вынесено в начало. Что защищает от распространенной ошибки, когда переменная не с того, не с сего стала глобальной из-за того, что банально забыли добавить объявление var.

Стрелочка -> заменяет слово function.
И еще обратите внимание, что нет необходимости добавлять слово return. Оно добавляется автоматически к последнему выражению в функции.

Значения параметров по умолчанию

CoffeeScript добавляет значения по умолчанию для параметров функций, чего нет в JavaScript.

Пример на CoffeeScript:
fill = (container, liquid = "coffee") ->
  "Filling the #{container} with #{liquid}..."

Эквивалент на JavaScript:
var fill;

fill = function(container, liquid) {
  if (liquid == null) {
    liquid = "coffee";
  }
  return "Filling the " + container + " with " + liquid + "...";
};

JavaScript-реализация сводится проверке параметра liquid на равенство null или undefined.
Другая деталь, которую иллюстрирует пример — в качестве выделения блоков используются не фигурные скобки, а отступы, как в Питоне.

Итерация свойств объекта

Другая вещь, которая раздражает в JavaScript — очень многословная итерация по свойствам объектов.
Дело в том, что в большинстве случаев при обходе объекта интересуют его собственные свойства, а не свойства прототипа.
А делать каждый раз for а в нем сразу же проверку hasOwnProperty немного утомляет.
Решение же в стиле jQuery.each() никто не запрещал, но оно уступает по эффективности дедовскому for.

Смотрим, как сделать круто:
yearsOld = max: 10, ida: 9, tim: 11

for own child, age of yearsOld
  console.log "#{child} is #{age}"  

Эквивалент:
var age, child,
  __hasProp = {}.hasOwnProperty;

for (child in yearsOld) {
  if (!__hasProp.call(yearsOld, child)) continue;
  age = yearsOld[child];
  console.log("" + child + " is " + age);
}

Приятные мелочи

В JavaScript оператор == ведет себя мягко говоря странно. Гораздо безопаснее использовать ===. Поэтому CoffeeScript преобразует оператор == в ===, оберегая начинающих разработчиков от подстерегающих в JavaScript ловушек. Хотя приходит в голову один случай, когда оператор == все-таки полезен. Это сравнение с null, которое позволяет проверить null и undefined одним махом. В CoffeeScript для этого предназначен оператор ?. Рассмотрим пример:
alert "I knew it!" if elvis?

И на выходе:
if (typeof elvis !== "undefined" && elvis !== null) {
  alert("I knew it!");
}   

Классы

Переходим к классам. На всякий случай уточним, что классами будем называть функции-конструкторы объектов.

Рассмотрим пример:
class Animal
  constructor: (@name) ->

  move: (meters) ->
    alert @name + " moved #{meters}m."

class Snake extends Animal
  move: ->
    alert "Slithering..."
    super 5

class Horse extends Animal
  move: ->
    alert "Galloping..."
    super 45

sam = new Snake "Sammy the Python"
tom = new Horse "Tommy the Palomino"

sam.move()
tom.move()

Даже интуитивно можно догадаться, что происходит. Описаны базовый класс Animal и два его наследника: Snake и Horse.
Обратим внимание на класс Animal. Запись @name в параметрах конструктора — это удобное сокращение, которое определяет свойство класса name и автоматически присваивает ему значение, передаваемое в конструкторе. В методе move запись @name — сокращение от this.name.

В методах move в подклассах super вызывает родительский метод с тем же названием. Ведь, и правда, когда мы находимся в дочернем классе, ссылка на родителя бывает нужна только для того, чтобы обратиться к одноименному методу родительского класса. Другие случаи даже в голову не приходят.

Не буду томить и, наконец-то, перейдем к js-варианту наших классов.
var Animal, Horse, Snake, sam, tom, _ref, _ref1,
  __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };

Animal = (function() {
  function Animal(name) {
    this.name = name;
  }

  Animal.prototype.move = function(meters) {
    return alert(this.name + (" moved " + meters + "m."));
  };

  return Animal;

})();

Snake = (function(_super) {
  __extends(Snake, _super);

  function Snake() {
    _ref = Snake.__super__.constructor.apply(this, arguments);
    return _ref;
  }

  Snake.prototype.move = function() {
    alert("Slithering...");
    return Snake.__super__.move.call(this, 5);
  };

  return Snake;

})(Animal);

Horse = (function(_super) {
  __extends(Horse, _super);

  function Horse() {
    _ref1 = Horse.__super__.constructor.apply(this, arguments);
    return _ref1;
  }

  Horse.prototype.move = function() {
    alert("Galloping...");
    return Horse.__super__.move.call(this, 45);
  };

  return Horse;

})(Animal);

sam = new Snake("Sammy the Python");

tom = new Horse("Tommy the Palomino");

sam.move();

tom.move();

В основе наследования лежит вариация классической функции extend.
Реализация достаточно простая. Конечно, если сравнивать с другими JavaScript библиотеками, которые предоставляют удобную кросс-браузерную реализацию классов на чистом JavaScript.
Минус навороченных библиотек в том, что не всегда легко разобраться, как они работают внутри.
А функция extend очень хорошо описана во множестве источников, например, здесь javascript.ru/tutorial/object/inheritance#nasledovanie-na-klassah-funkciya-extend.

Эффективность

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

Рассмотрим очень простой класс:
class Foo
  bar: 10

На выходе имеем JavaScript:
var Foo;

Foo = (function() {
	function Foo() {}
	Foo.prototype.bar = 10;
	return Foo;
})();

Здесь используется, так называемая асимметричность свойств объекта на чтение и на запись.
В реальной жизни значение свойства по умолчанию практически всегда выгодней добавлять в прототип объекта.
Пока нам не понадобится изменить это значение по умолчанию, мы не тратим лишнюю память для каждого объекта определенного класса. Но, допустим, мы решили изменить значение данного свойства так:
obj = new Foo() 
obj.bar = 500

Здесь создается персональное свойство bar у объекта obj. При этом свойство bar прототипа объекта obj по-прежнему равно 10. Все безопасно и эффективно.

Единственное, что может смущать в этом подходе, что при обращении к свойству, которое находится в прототипе, приходится продвигаться по цепочке прототипов. А это дается не бесплатно. Но на современных движках это не существенно, тем более на фоне радикальной оптимизации использования памяти, ну а старые IE-ки, в которых ощущалась деградация, постепенно уходят в небытие.

Назначение обработчиков событий

Другая крутая фича — назначение обработчиков событий для методов объектов. Пример:
Account = (customer, cart) ->
  @customer = customer
  @cart = cart

  $('.shopping_cart').bind 'click', (event) =>
    @customer.purchase @cart

Выдача:
var Account;

Account = function(customer, cart) {
  var _this = this;

  this.customer = customer;
  this.cart = cart;
  return $('.shopping_cart').bind('click', function(event) {
    return _this.customer.purchase(_this.cart);
  });
};

Чтобы в качестве обработчика события указать метод этого же объекта на чистом JavaScript, приходится выкручиваться.
Один из самых распространенных способов — создание замыкания. В CoffeeScript этот костыль не нужен. Достаточно функцию обработчика указать не как ->, а =>. После этого this внутри обработчика будет ссылаться на базовый объект.

Интеграция с чистым JavaScript

Если потребуется подключить чистый JavaScript-код, то это также просто сделать:
hi = `function() {
  return [document.title, "Hello JavaScript"].join(": ");
}`

На выходе получаем:
var hi;

hi = function() {
  return [document.title, "Hello JavaScript"].join(": ");
};

Массивы

Ну и конечно, присутствует много фишек для работы с массивами и объектами. Для иллюстрации рассмотрим одну.
Например, пусть мы хотим получить массив кубов чисел от 1 до 5.

В CoffeeScript достаточно написать:
cubes = (Math.pow(num, 3) for num in [1..5]) 

В многословном JavaScript получаем:
var cubes, num;

cubes = (function() {
  var _i, _results;
  _results = [];
  for (num = _i = 1; _i <= 5; num = ++_i) {
      _results.push(Math.pow(num, 3));
  }
  return _results;
})();

Заключение


Надеюсь, для знакомства должно хватить. Дальше добро пожаловать на coffeescript.org.

Ну и как положено, несколько выводов:
  • CoffeeScript увеличивает выразительность кода, упрощает и ускоряет как первоначальную разработку, так и дальнейшую поддержку кода.
  • Обучение очень быстрое (мне хватило пару дней втянуться).
  • Удобная поддержка со стороны WebStorm (Для других IDE тоже есть плагины, но про их качество ничего не могу сказать)
  • Большое community
  • Уберегает особенно начинающих разработчиков от многих ошибок.

Главное — понимать, что генерирует CoffeeScript. Тогда он превращается из лишнего подозрительного слоя абстракции в мощный инструмент.
Сергей Коржнев @ks7it
карма
13,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (76)

  • –1
    Вот скажите плиз, есть такой снипет

                 $('div').hover(function(e){ ...}, function(e) {... })
         


    Как это будет на coffeescript?
    • +1
        $('div').hover(
            ((e) -> ...),((e) -> ...)
        )
      
      • –1
        Ну то есть что было то и получил.
        • +1
          Можно проще:

          $('div').hover \
            (e) -> 1,
            (e) -> 1 
          
          
        • 0
          Ну тут упрощать-то и некуда особо, разве что скобки убрать:

          $('div').hover(
            (e) -> ,
            (e) ->
          )
          
          • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Я наоборот, обычно избавляюсь от скобок, но оставляю запятые:
              $('div').hover (e) ->
                      console.log 'success', e
                  , (e) ->
                      console.log 'err', e
              
        • 0
          Если вам нужно еще проще, то используйте LiveScript, там такая запись будет выглядеть так:

          $ \div .hover (e) ->,  (e) ->
          
          • +5
            Я не очень понимаю, что именно тут проще.
            Просто прихожу к выводу, что лично мне кофескрипт совсем не нужен, лучше дождаться Harmony и иметь шоткат для функций. Этого вполне хватит.
    • 0
      Я бы так записал:
      $("div").hover (e) ->
        ...
      ,(e) ->
        ...
      

      А вообще, по мне так самый полезный сайт для обучения coffee script, это вот этот — js2coffee.org/
      Это конвертер из java script в coffee script и обратно
      • 0
        Ваш код не валиден

        PS: не заметил пробел
        • 0
          пробелы очень важны в coffee script, это да
      • 0
        Знаю я этот сайт, как раз на моем примере он генерит неправильный код.

        Хотя нет, сейчас уже правильный но лишние скобки не убирает

        Исходный
        $('div').hover(function(e){ $(this).find('span').show()}, function(e) { $(this).find('span').hide()})
        


        Получилось
        $("div").hover ((e) ->
          $(this).find("span").show()
        ), (e) ->
          $(this).find("span").hide()
        


        И назад

        $("div").hover ((e) ->
          e.find("span").show()
        ), (e) ->
          e.find("span").hide()
        
        • 0
          И назад

          $("div").hover((function(e) {
            return e.find("span").show();
          }), function(e) {
            return e.find("span").hide();
          });
          
        • 0
          Я ввел:
          $('div').hover(function(e){1}, function(e) {1})
          

          Получил:
          $("div").hover ((e) ->
            1
          ), (e) ->
            1
          


          Так что код правильный, хотя, можно обойтись без скобок вокруг первой функции
  • 0
      $('.shopping_cart').bind 'click', (event) =>
        @customer.purchase @cart
    

    Как обратиться к свойствам обычного this?
    • 0
      Сам элемент можно получит как event.target. Есть ли кейсы, когда на самом деле нужен исходный this в этом примере?
    • +1
        _this = @
        $('.shopping_cart').bind 'click', (event) ->
          _this.customer.purchase _this.cart
          # @ - "обычный" this. 
      
  • 0
    Но у CoffeeScript, есть преимущество, что ему не нужно сохранять совместимость с JavaScript...

    Не нужно, но сохраняют совместимость с IE6 / ES3. В итоге получаем отсутствие поддержки нативных геттеров / сеттеров ES5 без костылей, большей части фишек ES6. Цитата:
    Q: Will you add feature X where feature X depends on a platform?

    A: No, implementation-specific features are not allowed as a policy. Everything that you write in CoffeeScript should be supported and runnable on any current JavaScript implementation (in practice, this means the lowest common denominator is IE6). Thus, features such as the following will not be implemented: getters & setters, yield
    • 0
      В IE геттеры/сеттеры появились только в 9-ке. В IE8 из ES5 реализовано крайне мало. А IE8 пока в большинстве случаев стараются поддерживать. Поэтому, если говорить про браузерный JavaScript, то ES5 можно использовать, к сожалению, далеко не везде.
      Но в целом политика партии с поддержкой IE6, конечно, сдерживает сам язык, согласен.
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Можно еще таким способом подключать: http://coffeescript.org/#scripts.
      Но он не рекомендуется.
    • 0
      Есть.
      <script src='/coffee-script.js'></script>
      <script src='/app.coffee' type='text/coffeescript'></script>
      
      Но в этом есть смысл только на этапе разработки — лишняя работа на клиенте.
    • +1
      Зачем? Разберитесь с отдельной тулзой лучше, а лучше с командной строкой.

      coffee --watch --map
      будет сразу создавать source map и chrome developer tools к примеру, будет указывать ошибки именно в coffeeScript, а не в созданном из него js.
  • +1
    Если использовать jquery, то последнюю задачу можно решить тоже очень красиво и без coffeescript:

    $(Array(5)).map(function(i) { return Math.pow(++i, 3); });
    • +4
      Я большой поклонник кофискрипта, но если вам он нужен только ради методов, вроде map, лучше обратить внимание на Underscore.js. Если вы из тех везунчиков, которым плевать на ИЕ8 и ниже, то даже библиотек никаких не нужно.
      • +4
        И нативный map, и undescore дырки в массиве, в отличии от jquery, пропускают. И правильно делают.
        Это я к тому, что
        _.map(Array(5),function(i){return Math.pow(++i, 3)}) //=> [undefined × 5]
        
  • 0
    А прикольно.

    Правильно ли понимаю, что конец определения класса определяется только отступом? И функции?
    • +2
      Да, как в питоне или фортране, все зависит от идентации.
      • 0
        Забавно до чего доходит экономия :-)
        • +1
          На самом деле это вопрос привычки, через пару недель питона, coffe, sass/haml etc к форматированию отступами быстро привыкаешь и перестаешь обращать внимание.
  • 0
    CoffeeScript очень хорошо сочетается с ExtJS, помогает бороться с большой вложенностью декларативного кода.
  • 0
    Вот не понимаю: почему CoffeeScript так активно развивается и поддерживается, — в то время как ES6 Harmony, или, там, JS 1.7, 1.8 никому особенно не интересны? Ведь ES6 это развитие языка, тогда как CoffeeScript — странная побочная альтернатива.
    Я бы с удовольствием переходил на новую версию JS с новыми фичами, чем на побочное отвтвление. Судя по описаниям возможностей, ES6 переплевывает Coffee.
    Технически ведь разницы между ними нет — транслятор имеется как для Coffee, так и для ES6.
    • 0
      Где есть транслятор ES6?
      • 0
        • 0
          Посмотрел. Я так понял это далеко не полный транслятор. Если тут перечислены все фичи, то в coffescript реализовано почти всё из этого, и ещё намного больше. Вряд ли все фичи ES6 можно эмулировать в ES5.
    • +1
      Потому что развивать побочный язык, где что хочешь, то и делаешь, развивать гораздо проще, чем уже существующий стандарт, где есть много заинтересованных игроков, от которых зависит его поддержка, стараясь при этом учесть все пожелания и каждую деталь.
    • 0
      ES6 переплевывает Coffee.

      Просто тут далеко не полное описание. В основном возможности соответствуют — arrow function (в ES6 только с лексическим this), rest/spred, генераторы, классы, деструктивное присваивание, аргументы по умолчанию, прочее… В IcedCoffeeScript await/defer сильно упрощает работу с асинхронными функциями — конечно не yield, но хоть что-то.
      ES6 хорош скорее не синтаксисом, а расширением стандартной библиотеки — хотя бы Proxy чего стоит.
      А вот по краткости и выразительности синтаксиса и кофе, и ES6 делает уже упомянутый в комментариях LiveScript.
      • 0
        Посмотрел LiveScript — он невероятно хорош собой.
        Игрался с Coffee, наткнулся на банальные проблемы:
        1. Вызов функций теперь работает так: some_func param1, param2. Но как вызвать функцию без параметров? Приходится опускаться до JS-нотации: some_func(). В чем тогда смысл сокращенной нотации вызова функций, если можно все делать по-старинке? В LiveScript все просто: some_function!
        2. Как заэкстендить объект в Coffee? — писать boilerplate code, который и в обычном JS пришлось бы писать. В LiveScript всё просто:
        one = {a:1, b:2}
        two = {b:3, c:4}
        one <<< two
        

        А если нужно один объект заэкстендить через прототип:
        one = one with two
        


        В остальном по мелочам в LiveScript много улучшений.
        Нехватает только guards и clauses, и будет эрланг.
        • 0
          1. По-видимому, разработчики CoffeeScript просто хотели быть ближе к Ruby, но не получилось до конца. При вызове функции без параметров и без скобок не понятно, то ли мы вызываем функцию, то ли используем ссылку на нее. Тупик. Поэтому многие разработчики предпочитают всегда указывать скобки для консистентности.
  • +6
    Напишем простенький код на CoffeeScript:
    square = (x) -> x * x
    cube   = (x) -> square(x) * x
    

    Его JavaScript-эквивалент:
    (function() {
        
    var cube, square;
    
    square = function(x) {
      return x * x;
    };
    
    cube = function(x) {
      return square(x) * x;
    };
    
    }).call(this);
    

    Неправда, это не эквивалент. Это избыточный результат компиляции. Вот эквивалент:

    function square(x) { return x * x; };
    function cube(x) { return square(x) * x; };
    
    • +1
      А напишите неизбыточный эквивалент объявления по условию:

      if prompt() == 'square'
        f = (x) -> x * x
      else
        f = (x) -> x * x * x
      
      • 0
        Math.pow(x, (prompt() == 'square'? 3: 2));

        var map = {square: 3};

        Math.pow(x, map[prompt()] || 2);
  • –1
    Кофескрипт, кофескрипт. Всё думал, что же он мне напоминает такое, и сейчас на ум сейчас приходит только сравнение с GUI-поделками для iptables — вроде всё есть, всё красиво показано, а как оно там скомпилируется одному богу известно.

    Я считаю, что хорошему программисту javascript не нужен кофескрипт или что нибудь подобное для того чтобы писать красивый код. От лукавого это всё.
    • 0
      Из своего опыта могу сказать, что вы не правы — все компилируется очень даже предсказуемо. Единственная, до сих пор сбивающая меня вещь — это то, что "==" заменяется на "===", а чтобы скомпилировалось в "==" надо писать «is»
      • 0
        is тоже компилируется в ===.
        • +2
          Я же говорю, сбивающая вещь.
    • +4
      C++, C++. Все красиво показано, а как оно там скомпилируется одному богу известно.
      Я считаю, что хорошему программисту assembler не нужен C++ или что нибудь подобное для того чтобы писать красивый код. От лукавого это всё.
      • 0
        Как скомпилируется известно как раз не богу, а хорошему программисту. Знание ассемблера нужно для того, чтобы знать как устроено, например, наследование, объекты и прочие вещи в C++ на низком уровне. Очень может быть полезно для систем, где критична скорость работы, да и вообще для понимая как устроены вещи.
        • +1
          Как же замечательно ваш комментарий переносится на JavaScript и CoffeeScript.
  • +1
    он позволяет нагляднее выражать свои мысли и понимать чужие.

    можете считать меня старым пердуном, но: не для одного мысли на CoffeeScript не выражаются нагляднее и не понимаются чужие?
    • +5
      Я перечитал нсколько раз, и так и не понял вашу мысль. Если вы так же пишите на js, как по-русски в этом комментарии, вам точно стоит попробовать CoffeeScript.
      • +7
        видимо вместо того, что бы писать коментарий мне надо было идти спать :)
        уже и не помнию, зачем я вообще его написал, но я вот к чему:

        сейчас идёт какая-то волна восхищения CoffeeScript, но как по мне — это тихий ужас: синтаксис нисколько не упрощает и не улучшает восприятие кода (сокращает количество строк да, но упрощением тут и не пахнет), все эти «->» «@» лишний визуальный мусор, отсутсвие фигурных скобок, обрамляющих тело функции, приводит к тому, что глазу не за что зацепиться и большой код превращается в кашу

        теперь любители CoffeeScript могут называть меня консерватором, боящимся перемен, и закидывать помидорами :)

        всё выше сказанное моё личное мнение.
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            конечно в IDE, просто со скобками чётче видно глазу, где функция начинается и заканчивается.

            опять же, это моё мнение. я на нём не настаиваю и никому не навязываю
            • НЛО прилетело и опубликовало эту надпись здесь
  • НЛО прилетело и опубликовало эту надпись здесь
    • –1
      Кстати, не лучше бы преобразовать в:

      [«x=»,x,«y=»,y].join('')

      ?
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          … что даже лучше.
      • +1
        На первый взгляд решение с массивом строк и join должно однозначно выполнятся быстрее.
        Ведь и правда, конкатенация большого количества строк в лоб, одну за другой должно создавать большое количество временных строковых объектов, которые потом надо вычищать сборщику мусора — это раз. Во-вторых, как не вспомнить легендарного маляра Шлемиэля (http://russian.joelonsoftware.com/Articles/BacktoBasics.html).

        Но все дело в том, что современные JavaScript движки достаточно умные, чтобы не хило оптимизировать конкатенацию.
        Подробно этот вопрос освещен здесь http://stackoverflow.com/questions/7299010/why-is-string-concatenation-faster-than-array-join.
  • +3
    Уберегает особенно начинающих разработчиков от многих ошибок.
    Совсем не согласен. Возможно это мой субъективный опыт, но делал очень много ошибок когда пытался кодить на CoffeeScript. Постоянно приходилось проверять всё ли правильно сгенерировалось. А это время и рассеивание внимания.

    Пропустил скобки, которые во многих случаях можно опустить — получил неверный вызов. Особенно тяжело отлавливать ошибки из-за разного количества строк в исходнике и компилириуемом файле. Можно, кончно, карту кода подцепить, но мы же говорим о начинающем программисте.

    Имхо CoffeeScript иструмент не для начинающего программиста, а скорее для того кто уже может абстрагироваться от языка.
    • 0
      Уберегает от ошибок именно в JavaScript. Но, конечно, открывает новые возможности — ошибиться в самом CoffeeScript. Это да. Другое дело, что возможностей выстрелить себе в ногу в чистом JavaScript гораздо больше.

      Согласен, крайне важный момент — соответствие между CoffeeScript и JavaScript-кодом. Без поддержки со стороны инструментальных средств я в принципе не представляю себе серьезную разработку на CoffeeScript. Для все того же WebStrom описание здесь — http://www.jetbrains.com/webstorm/webhelp/coffeescript-support.html
  • +3
    А мы после года разработки на CoffeeScript отказались от него. Синтаксические преимущества не всегда очевидны, полно узких мест, в которых парсер выдает не то, что задумывал автор. Скорость разработки не выросла, но и с дебагом даже до сорсмэпов проблем мы не испытывали. Получилось, что в целом «шило на мыло», и при прочих равных команда предпочла остаться на JavaScript в новых проектах.
    • НЛО прилетело и опубликовало эту надпись здесь
      • +1
        Естественно. WebStorm, SublimeText, GitHub, Jira, Jenkins, Confluence, Npm, LiveReload, etc.

        В конце 2011 — первой половине 2012 уже была волна перехода на Coffee. Тогда многие его пробовали, кто-то бросал после недели, кто-то — после месяца, кто-то через год, а кто-то продолжает до сих пор. И те, кто бросал, соглашались в одном — плюсы и минусы примерно равны, а раз нет разницы, то зачем заморачиваться?

        Сейчас идет вторая волна — из тех, кто в свое время струсил переходить на Coffee из-за якобы сложного дебага и решил дождаться выхода SourceMaps. Но для тех, для кого отладка с самого начала не была проблемой, ничего не изменилось.

        Если вам сегодня нравится Coffee, и вам он подходит, я рад за вас. Но для многих разработчиков это не шаг вперед, а шаг в сторону.
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            А JavaScript билда не требует? Конечно, можно не делать билда, но и CoffeeScript тоже можно скрипттагом подключать :) Мы так делали какое-то время, когда решали, пробовать — не пробовать. Даже @sourceUrl вставляли, чтобы в браузере заevalенные скрипты было видно, но быстро прекратили.

            Так никто не делает — в последний раз фронтенд проект без билда я видел году в 2009 или раньше. Наш билд-процесс компилирует стили, собирает скрипты в бандлы, прогоняется JSHint'ом по ним, спрайты пересобирает, если нужно, тесты прогоняет. Причем мало что изменялось при переходе с JS на CS и обратно. И я думаю, у многих так.
            • НЛО прилетело и опубликовало эту надпись здесь
              • +1
                Если они его не минифицируют, то почему бы комментариям не остаться? Кроме того, я вижу файл all.js — наверняка он не ручками собирается.
  • –1
    Почитал, хм, создалось ощущение, что этот сахар только будет усложнять понимание.
    В более многословном варианте всё-таки проще понять, что и где должно быть сделано
    • 0
      Добавление выразительных абстракций форсирует мышление. Синтаксические конструкции, которые делают ряд примитивных операций одним махом, позволяют лучше сфокусироваться на задаче и не раздувать код. Достаточно немного практики, чтобы привыкнуть к ним. В качестве бонуса будет легче изучать Python и Ruby. Просто потому, что CoffeeScript во многом опирался на эти языки.
  • +3
    Что ни говорите, но голый JS местами безобразный. Ну, для примера: объекты-классы без специальных оберток уродливы и нечитаемы. С чем-нибудь типа JSClass или Model.js, конечно, намного лучше, но это ведь еще одна библиотека на клиенте только ради красивого кода. А с Coffee все будут довольны: приятный глазу код у разработчика и скрипты без лишних модулей у клиента.

    Для меня с кофем также пропала нужда в шаблонизаторах там, где хватает встроенной интерполяции; больше не нужны jQuery-хелперы, да и вообще библиотеки с шортхендами и сахаром. Что-то стороннее подключается только чтобы не изобретать велосипед.

    Чтобы понять как все будет компилиться, достаточно внимательно прочитать страницу справки на сайте и вики на гитхабе и потом ручками переписать какой-нибудь готовый скрипт в split-view (чтобы js был виден в процессе), подглядывая в кукбук, но не в js2coffee (он на потом; нужно понимать как выглядел бы его вывод в идеале и подправлять вручную). Скомпиленный в итоге код не обязан быть идентичным, а то я гляжу, некоторые зачем-то пытаются этого добиться.
    Меня после описанных шагов настигло просветление, и я расстался с js раз и навсегда. (Ну почти навсегда — очень не хватает добротной CoffeeScript-консоли в панели разработчика, а к существующую приходится самому дописывать на досуге.)

    Можно не тратить время на спор со злыми дядьками, которые угорают по всему нативному, о полезности таких инструментов. Если бы были стандарты постарше — не без костылей совместимые с современными, и чтоб построже да понажористей, — эти дядьки бы только их и считали православными, а всё остальное — шайтанскими безделушками. Нами же, подсевшими на CoffeeScript, Slim и SASS, возможно как и их авторами, движет лень и утомление от дедовских методов.
  • 0
    Попробовал я CoffeScript и пока не впечатлился. Две вещи, которые я нашел странными в CS:
    1. Нету тернарного оператора, конструкция на CS получается страшнее чем на JS:
    healthy = if 200 > cholesterol then 1 else 0
    

    Даже «замена» тернарного оператора не поддерживает элементарный синтаксис, который я не часто использую, но всё же использую.
    let a = 1, b = a ? (console.log("good"), true) : false;
    

    на CS выдаёт синтактическую ошибку:
    a = 1; b = if a then (console.log "good", true) else false
    


    2. Деструктуризация не реализована полностью. Пока я натолкнулся на то, что не поддерживаются разряженные массивы в качестве шаблона для деструктуризации:
    arr = [1,2,3]
    [a, , b] = arr #тут ошибка
    
    • 0
      Поправка по первому пункту:
      Так работает
      a = 1; b = if a then (console.log "good"; true) else false
      
  • –1

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