CoffeeScript

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 00:07, 9 июня 2016.
CoffeeScript
CoffeeScript.png
Спроектировано Джереми Ашкенас
Портал: http://coffeescript.org/

CoffeeScript ([’kɔ:fɪ skrɪpt]; кофи скрипт) — компактный высокоуровневый язык программирования, транслируемый в JavaScript. CoffeeScript использует синтаксический сахар в стиле Ruby, Python, Haskell и Erlang, чтобы улучшить читаемость кода и уменьшить его размер. CoffeeScript позволяет писать более компактный код по сравнению с JavaScript. JavaScript-код, получаемый трансляцией из CoffeeScript, полностью проходит проверку JavaScript Lint.

Изначально компилятор языка был написан на Ruby. В версии 0.5, которая вышла 21 февраля 2010 года, компилятор был реализован на самом CoffeeScript. Язык был радушно воспринят в Ruby-сообществе. Встроенная поддержка CoffeeScript была добавлена в веб-фреймворк Ruby on Rails с версии 3.1.

Преимущества перед JavaScript

JavaScript на сегодня является одним из наиболее популярных и распространенных языков программирования. Он обычно используется как встраиваемый язык для программного доступа к объектам приложений. Наиболее широкое применение находит в браузерах как язык сценариев для придания интерактивности веб-страницам.

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

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

CoffeeScript во многом устраняет недостатки своего предшественника:

  • предоставляет простой синтаксис с меньшим количеством балласта;
  • использует пробелы как способ организации блоков кода;
  • обеспечивает простой синтаксис для выражения функций;
  • обеспечивает наследование на основе классов.

При этом CoffeeScript не является интерпретируемым языком и не использует отдельные библиотеки времени выполнения - весь код на CoffeeScript компилируется в соответствующий код на JavaScript. Таким образом, CoffeeScript предоставляет программисту синтаксис, который позволяет использовать всю силу JavaScript с минимальными накладными расходами.

Предварительные требования

CoffeeScript распространяется как пакет Node.js с помощью менеджера пакетов Node ― NPM. Таким образом, для написания и компиляции кода на CoffeeScript необходимо предварительно установить Node.Js. Кроме того, для работы потребуется среда исполнения JavaScript. Для этого подходит виртуальная машина JavaScript V8, лежащая в основе Node.js. Устанавливается CoffeeScript также как и другие пакеты Node.Js: npm install -g coffee-script

Компиляция

Чтобы запустить компилятор CoffeeScript, достаточно ввести команду coffee -c<имяфайла>: например coffee -ctest.coffee. Результатом выполнения команды будет одноименный файл .js с соответствующим кодом на JavaScript. Также можно указывать не только конкретный файл, но и папку, содержащую исходные коды: coffee --compile --output lib/ src/

Файл с исходным кодом test.coffee

console.log "Hello world"

Результирующий файл test.js

(function() {
    console.log("Hello world");
}).call(this);

JavaScript поддерживает определение области видимости только на уровне функции. Из-за этого компилятор CoffeeScript заключает код в анонимную функцию, тем самым гарантируя, что переменная будет ограничена только этой функцией и не станет глобальной (и не заменит существующую глобальную переменную).

Синтаксис

Функции

Напишем простые функции для возведения числа в квадрат и куб:

CoffeeScript JavaScript
square = (x) -> x * x
cube   = (x) ->
    square(x) * x
(function() {    
    var cube, square;

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

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

Объявление всех локальных переменных (в данном случае - имена функций, var cube, square) выносится в начало анонимной функции-ограничителя. Это помогает избежать распространенной ошибки, когда переменная становится глобальной из-за того, что программист забыл добавить объявление var. В то же время, объявленная на верхнем уровне вложенности переменная становится видна на более низких уровнях и может быть случайно изменена. Ключевое слово JavaScript function заменяется стрелкой ->. Ключевое слово return указывать необязательно - оно добавляется автоматически к последнему выражению в функции. Блоки формируются не фигурными скобками, а отступами, как в Python.

Условные операторы

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

CoffeeScript JavaScript
mood = greatlyImproved if singing

if happy and knowsIt
  clapsHands()
  chaChaCha()
else
  showIt()

date = if friday then sue else jill
var date, mood;

if (singing) {
  mood = greatlyImproved;
}

if (happy &amp;&amp; knowsIt) {
  clapsHands();
  chaChaCha();
} else {
  showIt();
}

date = friday ? sue : jill;

Форматные строки

CoffeeScript позволяет форматировать строки, указывая имена переменных в конструкции #{имя}:

CoffeeScript JavaScript
for i in [0..5]
  console.log "Hello #{i}"
(function() {
  var i;
  for (i = 0; i <= 5; i++) {
    console.log("Hello " + i);
  }
}).call(this);

Параметры по умолчанию

CoffeeScript JavaScript
fill = (container, liquid = "coffee") ->
    "Filling the #{container} with #{liquid}..."
var fill;
fill = function(container, liquid) {
  if (liquid == null) {
    liquid = "coffee";
  }
  return "Filling the " + container + " with " + liquid + "...";
};

Реализация на JavaScript сводится к проверке параметра, в случае равенства null или undefined параметру присваивается значение по умолчанию.

Операторы сравнения

В JavaScript оператор == зачастую может вести себя совершенно не так, как ожидает того программист. Безопаснее использовать === , поэтому CoffeeScript автоматически преобразует все операторы == в === . Тем не менее, возможна ситуация, когда потребуется использовать именно оператор == : к примеру, при проверке на существование (existence) значения переменной.

CoffeeScript JavaScript
alert "I knew it!" if elvis?
if (typeof elvis ! == "undefined" &amp;&amp; elvis ! == null) {
  alert("I knew it!");
}

Оператор ? позволяет проверять неравенство одновременно двум значениям: null и undefined.

Циклы и генераторы массивов

Низкоуровневые циклы в CoffeeScript реализуются посредством while. Основное отличие от JavaScript в том, что цикл while может быть использован как выражение, возвращая значение, содержащее результат каждой итерации в цикле. Для удобочитаемости, ключевое слово until эквивалентно while not, а loop соответствует while true.

CoffeeScript JavaScript
if this.studyingEconomics
  buy()  while supply > demand
  sell() until supply > demand
if (this.studyingEconomics) {
  while (supply > demand) {
    buy();
  }
  while (!(supply > demand)) {
    sell();
  }
}

Генерация массивов (также "списковое включение", list comprehension) - это способ компактного описания операций обработки списков и массивов в языках высокого уровня. В этом случае новый список формируется путём применения к уже существующему списку некоторой последовательности операций. Наиболее часто в CoffeeScript используются генераторы массивов, которые компилируются в стандартные циклы for. В отличие от циклов в JavaScript, генераторы массивов - это выражения, и они могут возвращать значения и присваиваться. Генераторы в состоянии обрабатывать большую часть случаев, где можно использовать циклы each/forEach, map и select/filter.

CoffeeScript JavaScript
cubes = (math.cube num for num in list)
cubes = (function() {
  var i, len, results;
  results = [];
  for (i = 0, len = list.length; i < len; i++) {
    num = list[i];
    results.push(math.cube(num));
  }
  return results;
})();

Для определения шага цикла можно использовать ключевое слово by, например: evens = (x for x in [0..10] by 2). Генераторы также могут быть использованы для перебора свойств и значений объекта. Используя ключевое слово of можно обращаться к свойствам объекта:

yearsOld = max: 10, ida: 9, tim: 11
ages = for child, age of yearsOld

Срезы массивов

Для работы с фрагментами массивов (срезами, slices) можно использовать диапазоны, определяемые двумя точками (..) . Так, диапазон arr[3..6], включает в себя 3, 4, 5 и 6 элемент массива arr. В диапазоне с троеточием arr[3...6] будет опущен последний элемент: 3, 4, 5. Некоторые индексы имеют значения по умолчанию: опущенный первый индекс по умолчанию имеет нулевое значение, а опущенный второй индекс по умолчанию указывает на размер массива. Срезы можно использовать также и для "блоковой" замены сразу нескольких элементов массива.

CoffeeScript JavaScript
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
start   = numbers[0..2]
middle  = numbers[3...6]
end     = numbers[6..]
copy    = numbers[..]
numbers[3..6] = [-3, -4, -5, -6]
var copy, end, middle, numbers, start, _ref;

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];
start = numbers.slice(0, 3);
middle = numbers.slice(3, 6);
end = numbers.slice(6);
copy = numbers.slice(0);
[].splice.apply(numbers, [3, 4].concat(_ref = [-3, -4, -5, -6])), _ref;

Встроенный JavaScript

CoffeeScript допускает использование фрагментов чистого JavaScript в коде. Для этого фрагмент JS-кода необходимо заключить в обратные кавычки.

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

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

Использование классов

Один из главных недостатков JavaScript заключается в его "нестандартном" стиле объектно-ориентированного программирования. В подавляющем большинстве случаев применяется ООП на основе классов, в JavaScript же объекты часто используются просто как коллекции. Кроме этого присутствует аж два способа описания классов - функциональный и прототипный. Кроме того, существует большое количество различных библиотек, предоставляющих программистам способы "традиционного" задания классов. Эти библиотеки могут значительно отличаться друг от друга, внося дополнительную неразбериху.

CoffeeScript предоставляет основную структуру class, которая позволяет задать имя класса, его суперкласс, присваивать прототипные свойства и определить конструктор.

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()

Оператор extends используется для создания цепочки наследований между классами; оператор :: позволяет обращаться к объектам прототипа, а вызов super() конвертируется в вызов метода класса-предка с тем же именем.

Запись @name в параметрах конструктора - это сокращение, которое автоматически определяет свойство name и присваивает ему значение, передаваемое в конструкторе. В методе запись @name - сокращение от this.name.

Ссылки