CoffeeScript в деле — Пять вещей, которые можно сделать и с JavaScript

Автор оригинала: Trevor Burnham
  • Перевод
От переводчика: В статье есть несколько JavaScript нюансов, которые могут быть интересны и тем, кто далек от CoffeeScript

Как и все программисты, я осторожен в отношение CoffeeScript. Как может, немного синтаксического сахара, оправдать дополнительный шаг компиляции?

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

1. Объявление переменных


Многие новички считают, что var x означает: «Я объявил переменную с именем Х». На самом деле, var, лишь предотвращает Х от роуминга за пределы текущей области. Если вы напишете:

x = 'Hello from the JavaScript Nation!';

и не будете использовать var, тогда X автоматически станет глобальной. Сделайте подобную ошибку в двух частях вашего приложения, и одна глобальная переменная будет перекрывать другую, создавая ошибку.

Даже опытные профи часто делают подобную ошибку, особенно когда объявляют переменные сцеплением: var a = 1, b = 2 и присваивают новое значение в пределах окружения, тогда как var a = 1; b = 2 присваивает значение, глобальной переменной b.

От переводчика: Для тех, кто сомневается, что может перепутать "," и ";" приведу другой пример: var a = b = 3

Путь CoffeeScript


С CoffeeScript, все переменные, автоматически попадают в текущее окружение. Когда вы пишете:

x = 'Welcome to CoffeeScriptville!'

вы можете быть уверены, что не переопределили какую нибудь глобальную переменную. Мало того, благодаря CoffeeScript компилятору, Х автоматические ограничивается текущим файлом.

2. Другой this


Один из самых распространенных источников путаници в JavaScript, ключевое слово this. Вы делаете простой вызов:

tinman.prototype.loadBrain = function() {
   this.brain = 'loading...';
   $.get('ajax/brain', function(data) { this.brain = data; });
};

но получаете ошибку, потому что, внутри вызова данных, this указывает не на тот же объект, на который он указывал, за ее пределами.

Путь CoffeeScript


Во-первых, ключевое слово this, имеет псевдоним @, для того, что бы было визуальное отличие от обычных переменных.

Во-вторых, для того, что бы передать переменные @ в связанную функцию, необходимо использовать => (жирная стрелка), в отличие от обычного символа ->, объявляющего функцию:

tinman::loadBrain = ->
  @brain = 'loading...'
  $.get 'ajax/brain', (data) =>
    @brain = data

3. Сокращенные условия


Тернарный оператор, занимает особое место в JavaScript: В отличие от других условных структур (if, switch), он возвращает результат. Это означает, что программисту приходится выбирать, между краткостью тернарного оператора:

closestEdge = x > width / 2 ? 'right' : x < width / 2 ? 'left' : 'center';

или логической цепочкой:

if (x > width / 2) {
  closestEdge = 'right';
} else if (x < width / 2) {
  closestEdge = 'left';
} else {
  closestEdge = 'center';
}

Путь CoffeeScript


Все условия в CoffeeScript, возвращают результат. Это дает нам ясный второй подход, без бессмысленного повторения:

closestEdge =
if x > width / 2
  'right'
else if x < width / 2
  'left'
else
  'center'

4. Асинхронный функционал


Популярный тест «Так ли хорошо вы знаете JavaScript» содержит задачу:

for (var i = 1; i <= 3; i++) {
  setTimeout(function() { console.log(i); }, 0);
}

результат будет:
4
4
4

Почему? Даже если в setTimeout таймаут равен 0, данная функция заработает только после завершения цикла. И когда функция выполнится, i будет равно 4-ом. Для того, что бы захватить каждое значение i, вам придется выполнить:

for (var i = 1; i <= 3; i++) {
  (function(i) {
    setTimeout(function() { console.log(i); }, 0);
  })(i);
}

Путь CoffeeScript


Хотя, CoffeeScript не захватывает автоматически переменные в цикле, он дает возможность сделать краткий захват:

for i in [1..3]
  do (i) ->
    setTimeout (-> console.log i), 0

результат будет:
1
2
3


5. Повторение, повторение


Код говорит сам за себя:

x = sprite.x;
y = sprite.y;
css = {
  opacity: opacity,
  fontFamily: fontFamily
};
function(request) {
  body = request.body;
  status = request.status;
  // ...
}

Путь CoffeeScript


Каждый фрагмент выше, превращается в одну строчку:

{x, y} = sprite
css = {opacity, fontFamily}
({body, status}) -> ...

Заключение


CoffeeScript это не только более красивый код, речь идет о более гибком коде. Речь идет, о большей уверенности, что вы сделаете правильный код с первого раза, и легко изменените его в будущем.

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

(Конечно, если вы обновитесь до Rails 3.1, у вас не будет выбора)
От переводчика: Что бы не вводить никого в заблуждение, скажу, это шутка! Выбор конечно есть, достаточно убрать строчку из Gemfile.

От переводчика: Поздравляю всех RoR разработчиков с выходом Rails 3.1 beta 1. Все не точности в переводе, прошу слать в ЛС.
Поделиться публикацией

Похожие публикации

Комментарии 45

    +4
    КофиСкрипт — получается, это не фреймворк, а отдельный скриптовый язык, компилируемый в ЯваСкрипт? Интересно. Конструкции языка чем-то похожи на Питон.

    В чем преимущество такого подхода перед использованием ЯваСкриптовых фреймворков?
      0
      Это язык для упрощенной генерации Javascript. CoffeeScript не отменяет использования javascript фреймворков и прекрасно работает с ними, только синтаксит становится удобнее, а в остольном вы так же используете свой любимый JQuery или что то другое. Если вы работает с HAML + SASS, вам должно быть это знакомо
        0
        Отлично! Спасибо.
        Обзор получился замечательный: кратко и емко!
      +9
      Даже опытные профи часто делают подобную ошибку, особенно когда объявляют переменные сцеплением: var a = 1, b = 2 и присваивают новое значение, глобальной переменной b.


      весьма странное предположение
        –1
        все уже исправлено, спасибо andy128k, за то, что написал мне об этом в ЛС, как я и просил…
          0
          Всё равно предположение осталось странным. Профи путают запятую и точку с запятой? Я и новичком-то их никогда не путал.
            +1
            Дополнил статью собственным, более реальным примером
              +8
              Оба примера притянуты за уши:


              Более того, в разделе "Lexical Scoping and Variable Safety" видно, что, в CoffeeScript, в отличии от JavaScript нифига не понятно!

              Смотрим пример:

              changeNumbers = ->
                inner = -1
                outer = 10
              inner = changeNumbers()
              


              Во что оно трансилоровалось?

              changeNumbers = function() {
                var inner;
                inner = -1;
                return outer = 10;
              };
              


              Прекрасно! Иннер взялась из внутреннего контекста, и аутер — из внешнего. И в большой коде, если где-то затесался счётчик — всё сломается. Мы не контролируем область видимости, а надеемся, что CoffeeScript нас правильно поймёт

              Асинхронный функционал

              Рефакторинг спасёт вас, а не CoffeeScript. В CoffeeScript точно так же можно допустить ошибку, так что это лукавство:
              for i in [1..3]
                setTimeout (-> console.log i), 0
              


              Разделите на методы, как завещал старый, но умный дедушка Фаулер:
              loop: function () {
              	for (var i = 1; i <= 3; i++) {
              		this.asyncLog(i);
              	}
              },
              asyncLog: function (i) {
              	setTimeout(function() { console.log(i); }, 0);
              }
              


              А если принципиально не создавать метод — воспользуйтесь новым методом «bind» ( + compatibility для старых браузеров )
              for (var i = 1; i <= 3; i++) {
              	setTimeout(console.log.bind(console, i), 0);
              }
              

              Не аргумент.

              Короче, рубисты не хотят учить JavaScript, потому сделали из прекрасного языка что-то похожее на Руби. Осуждаю.
                +2
                  +2
                  Аргументов, в общем, нету, ага?
                    –2
                    Сомневаюсь, что в Rails Core Team сидят ребята, не знающие JS.
                      0
                      Аргумент, да =)))
                        0
                        Возможно. Однако разработчиков, использующих RoR, которые отлично знают JavaScript и его тонкости значительно меньше — для них и ввели CoffeScript, это ж очевидно.
                    –3
                    толсто.
                    changeNumbers = ->
                    inner = -1
                    outer = 10
                    inner = changeNumbers()

                    inner()


                    транслируется в(function() {
                    var changeNumbers, inner;
                    changeNumbers = function() {
                    var inner, outer;
                    inner = -1;
                    return outer = 10;
                    };
                    inner = changeNumbers();
                    inner();
                    }).call(this);


                    или вам нужны какие-то лишние переменные в контексте? тогда удачи.

                    стыд, позор и общественное порицание вам. жир утрите с монитора
                      0
                      Идиот, перейди по ссылке jashkenas.github.com/coffee-script/, перейди к разделу «Lexical Scoping and Variable Safety» и посмотри первый пример. Если переменная есть в глобальном контексте, то в локальном ей не будет добавляться «var». Я специально дал ссылку и точное название раздела, но ты или тугой, или слепой.

                      Когда посмотришь пример протри слюни с монитора.

                        +1
                        умный вы наш, куски кода копипастить без контекста. по ссылке вашей никто ходить не будет, все будут смотреть в код и испражняться кирпичами

                        если переменная есть в глобальном контексте, то называть её так же в локальном не комильфо, мягко говоря. если так делаете, то у вас с кодом что-то не то.

                        удачи по жизни в конструктивном общении, ага
              0
              На самом деле бывает и такое. Но у опытных разработчиков это называется описка ;)
              +4
              Отладку делать всё равно в нормальном javascript и тут мозги вскипят: весь код вроде бы тот же, да не тот.
                0
                [irony]Код true-программистов не нуждается в отладке...[/irony]

                Восторженные возгласы резко сменятся гневом после обнаружения первой же ошибки компилятора.
                  +1
                  ну… как бэ одна из основных фич TDD — это перенести процесс отладки в процесс написание тестов.

                  Т.е. есть баг — пишешь тест, проявляющий баг, фиксишь, тестишь, еще раз фиксишь, проверяешь чтоб тест не валился.

                  Так что не такой уж это и «ирони» как казалось-бы :)
                    0
                    А «фиксишь» не подразумевает отладки?
                      0
                      Даже странно, но в теории — нет (на практике мне лично все-же иногда приходится дебажить чтоб узнать почему именно получился такой результат вместо ожидаемого, но это скорее из-за плохой организации той системы, с которой я работаю).

                      Под «фиксишь» я имел ввиду именно изменение кода, необходимое для того, чтоб тест не зафейлился.

                      А отличие TDD от просто наличия тестов во время правки багов заключается в том, что сначала пишется тест, в котором заключается описание бага. Типа ожидали вот это. И еще во время написания теста уже приходит мысля как именно исправить код, чтоб тест прошел.
                        0
                        это не теория. это религия. баги не пишут только те, кто ничего не делает. 100% покрыть тестами можно только абсолютную пустоту. а баги не всегда так очевидны, чтобы достаточно было взглянуть на код. да и на какой код смотреть — это ещё предстоит узнать.

                        narod.ru/disk/12010544001/%D0%9B%D0%BE%D0%B2%D1%83%D1%88%D0%BA%D0%B0%20%D0%B4%D0%BB%D1%8F%20%D0%B1%D0%B0%D0%B3%D0%BE%D0%B2.pptx.html
                          0
                          Странные высказывания.

                          100% покрывается код при использовании TDD: т.е. когда всегда код пишется после написания теста. Практика показывает, что в таком случае выходит как бы даже больше 100% — один тест идет до написания кода, и потом еще пару «закрепляющих» которые тестируют граничные условия.
                  –6
                  Извините, не хочу показаться грубым, но заходя в ваш профиль я был уверен что вам за 30-ть. И по видимому не ошибся.

                  До знакомства с CoffeeScript, я пару лет пользовался HAML(язык разметки для упрощённой генерации XHTML) и не разу у меня не возникало никаких проблем с отладкой. Более того, отладка упростилась. То же можно сказать и про SASS

                  На данную тему есть отличная статья, "Очнитесь, на дворе XXI век", она подходит для любого языка, если читать между строк.

                    +5
                    ыть… а что, сейчас «за 30-ть» — это критерий?

                    Я вот прямо скажу — мне «за 30-ть», но слежу за с++0x (даж gcc 4.6 ради этого прикрутил), node.js, GAE, GWT, стараюсь следить за алгоритмами, базами данных — редиску у себя на компе крутил так и сяк, HTML5+CSS3 курю… Вот после 10+ лет использования MS-продуктов перешел дома на ubuntu.

                    Хотя работаю я с enterprise-level .NET: C#, ASP.NET, Win7/Server, MSSQL и прочие прелести.

                    Так что вот не надо, пожалуйста, про «за 30-ть».

                    ПС. это был оффтоп, но вместо «у меня не возникало никаких проблем» можно было бы ссылочку на то как именно дебажить кофискрипт по кофискриптовскому исходнику а не по JS, который получился.
                      –3
                      Дело не в возрасте, а в мировозрение и стремление постигать новое. Не хотел не кого задеть или обидеть.
                        0
                        Человек вам прямо написал, что ему за 30 и его стремление постигать новое достойно зависти.
                      0
                      Но ведь там та же конструкция не принимает обратный смысл? ;-)
                      (подразумеваю var, вернее его отсутствие)
                    +5
                    Очень смущает "->" и "=>". Делая часто код ревью скажу, что если язык пропускает похожие символы не меняя семантики (т.е. компилироваться будет + даже запускаться иногда без проблем будет пока не заюзают "@"), то это приводит к очень неприятным трудноуловимым последствиям.

                    Да, конечно, краткость — сестра таланта. Но имея продвинутые IDE (с хорошей системой дополнений) и снипетов с генераторами, лучше иметь чуть больше кода, чем потом сидеть и всматриватся в симолы ловя отличия между "-" и "=".

                    Очень не хочется поиметь еще один язык, позволяющий писать write-only конструкции.

                    ПС. В принципе то же относится к "(" и "{" — если синтаксис языка позволяет подменять одно на другое, но от этого сильно меняется результат — это тоже не есть гуд.

                    К примеру кусок из статьи:
                    setTimeout (-> console.log i), 0

                    не знаю, как в кофи-скрипте, но выглядит это как вызов функции setTimeout с одним параметром и потом простое выражение «0». Если это не так, и ",0" — второй парамтр, то появляется вопрос как читать вот такие конструкции:
                    somefunc param1, another_func param2, param3
                    А именно param3 передется первой функции или второй.
                    Ну и плюс
                    somefunc (x), y = y + 1
                    и т.д.

                    В общем, очень интересно, но немного пугает кажущаяся неоднозначность языка (да, можно читать мануалы, но...)
                      +2
                      Синтаксический диабет. Еще чуть-чуть сахара и писец.
                      0
                      Поправки:

                      1) очень многие проблемы JavaScript решаются с помощью «use strict», в том числе, — неявное объявление переменной недопустимо;
                      2) С выходом Rails 3.1 выбор останется, просто CoffeeScript будет включен по умолчанию. Никто не мешает его убрать из Gemfile. Вообще, там целый холивар — github.com/rails/rails/commit/9f09aeb8273177fc2d09ebdafcc76ee8eb56fe33#comments

                      image

                      image

                      image

                      +1
                      Про «нет выбора» — мне кажется надо как-то пометить, что это шутка. А то многие прочитаю, подумают что dhh совсем ебанулся и заставляет всех учить кофескрипт, а иначе вон из профессии.

                      Там просто он по-умолчанию предлагается. Во-первых, никто не заставляет юзать, во-вторых, поддежку тоже можно убрать удалив одну строку из гемфайла.
                        0
                        спасибо за замечание, дополнил статью
                        –1
                        > Конечно, если вы обновитесь до Rails 3.1, у вас не будет выбора
                        то, что написано на том сайте по ссылке, грубо говоря, — бред. как уже говорили выше, никто не запрещает стеререть одну строчку в Gemfile, или вовсе ничего не удаляя, продолжить писать в обычные JS файлы.

                        белки_истерички.jpg
                          +1
                          обещаю, в следующий раз я буду обновлять комментарии перед тем, как жать на кнопку.
                          +1
                          По-моему какие-то надуманные проблемы. Особенно с var, this и setTimeout.
                            +1
                            не больше, не меньше як просто адаптация синтаксиса под Ruby. Если хорошо понимаешь тонкости языка, то можешь использовать их во благо ;)
                              0
                              Кстати мне показалось что больше не под Ruby, а под Python. Эти отступы, конструкции вида «1 > x > 3», и т.д. Надо конечно больше с ним поработать, но чувствуется какая-то небрежность синтаксиса, что ли…
                              0
                              По этим примерам, у меня напрашивается вывод, что CoffeeScript не нужен если понимаешь JS.
                                +1
                                Много лишних запятых. Очень. Вы прям маньяк.
                                  –2
                                  Хочется CoffeeScript для PHP…
                                    –1
                                    «Я стал писать код быстрее, и с меньшим количеством ошибок, потому что он, стал намного чище.» Я бросил нудную работу и нашел новую с высокой зарплатой. Я познакомился с прекрасной женщиной, которая стала матерью моих замечательных детей. Теперь у меня есть квартира с пентхаусом, красная феррари, личный вертолет и солидный счет в швейцарском банке.

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

                                    Самое читаемое