CoffeeScript — язык программирования, транспилируемый в JavaScript. CoffeeScript добавляет синтаксический сахар в духе Ruby, Python, Haskell и Erlang для того, чтобы улучшить читаемость кода и уменьшить его размер. CoffeeScript позволяет писать более компактный код по сравнению с JavaScript. JavaScript-код, получаемый транспиляцией из CoffeeScript, полностью проходит проверку JavaScript Lint.
История Создателем языка является Джереми Ашкенас.
Изначально компилятор был написан на Ruby, но в версии 0.5, которая вышла 21 февраля 2010 года, компилятор был реализован на самом же CoffeeScript.
CoffeeScript был радушно воспринят в Ruby-сообществе. Встроенная поддержка CoffeeScript была добавлена в веб-фреймворк Ruby on Rails с версии 3.1.
Преимущества использования Использование пробелов как разграничительных знаков (вместо скобок, точек с запятой и прочих) делает CoffeeScript кратким. По сравнению с JavaScript строка для того же конкретного кода в CoffeeScript сокращается примерно до половины (примерно на 55 % меньше). Также CoffeeScript позволяет избежать проблем с объявлением области действия в программе, поскольку, в отличие от JavaScript, использовать ключевое слова var перед объявлением переменной не требуется. Помимо этого, в CoffeeScript есть ряд удобных функций, таких как осмысление массивов, псевдонимы прототипов и классы, которые ещё больше сокращают количество вводимых символов.
Недостатки использования Дополнительный этап компиляции между написанным кодом и кодом на JavaScript увеличивает общее время компиляции программы. CoffeeScript не является широко используемым, из-за чего сложнее искать источники информации по нему и кооперировать с другими разработчиками
Синтаксис
Особенности отсутствие точек с запятой (при этом, в самом JavaScript использование точек с запятой не обязательно, хоть и рекомендуется) фигурные скобки {} заменены табуляцией
Комментарии В CoffeeScript синтаксис для комментариев заимствован из Ruby, где каждый однострочный комментарий начинается со знака решетки #, а многострочные комментарии заключены между тремя символами решетки:
CoffeeScript: # однострочный комментарий
многострочный комментарий
JavaScript: // однострочный комментарий
/* многострочный комментарий */
Пробелы Подобно языку Python, CoffeeScript использует табуляции для обозначения блоков кода.
Переменные Неподдерживаемость CoffeeScript глобальных переменных предотвращает ошибки доступа, которые могли возникнуть в JavaScript при случайном объявлении глобальной переменной.
CoffeeScript: myVariable = "test"
JavaScript: let myVariable = "test";
Функции CoffeeScript удаляет довольно многословный оператор функции и заменяет его тонкой стрелкой: ->. Функции могут быть однострочными или отступать на несколько строк. Последнее выражение в функции неявно возвращается.
CoffeeScript: func = -> "bar"
func = -> # An extra line "bar"
JavaScript: function func() { return "bar"; }
// другой вариант (с использованием стрелочной функции) let func = () => "bar";
Аргументы функций Аргументы функции записываются в круглые скобки перед стрелкой. Есть поддержка аргументов по умолчанию.
CoffeeScript: times = (a = 1, b) -> a * b
JavaScript: function times(a = 1, b) { return a * b; }
// другой вариант let times = (a = 1, b) => a * b;
Также можно использовать для приема нескольких аргументов.
CoffeeScript: a = "Howdy!"
alert a # Equivalent to: alert(a)
alert inspect a # Equivalent to: alert(inspect(a))
JavaScript: let a = "Howdy!";
alert(a);
alert(inspect(a));
Вызов функций Функции можно вызывать точно так же, как и в JavaScript: с помощью скобок (), .apply() и .call(). Однако, как и в Ruby, CoffeeScript автоматически вызывает функции, если они вызываются хотя бы с одним аргументом.
Объектные литералы и объявление массивов Объектные литералы задаются точно так же, как и в JavaScript, с помощью пары скобок и операторов ключ/значение. Однако, как и в случае с вызовом функций, в CoffeeScript скобки необязательны. Вместо запятых можно использовать отступы и новые строки.
CoffeeScript: object1 = {one: 1, two: 2}
# Without braces object2 = one: 1, two: 2
# Using new lines instead of commas object3 = one: 1 two: 2
User.create(name: "John Smith")
JavaScript: let object1 = { one: 1, two: 2 } let object2 = { one: 1, two: 2 } let object3 = { one: 1, two: 2 }
User.create({ name: "John Smith" });
Аналогично, в массивах вместо запятых могут использоваться пробельные символы, хотя квадратные скобки ([]) по-прежнему обязательны.
CoffeeScript: array1 = [1, 2, 3]
array2 = [ 1 2 3 ]
array3 = [1,2,3,]
JavaScript: let array1 = [1, 2, 3];
let array2 = [ 1, 2, 3 ];
let array3 = [1, 2, 3,];
Условные операторы Если оператор if расположен в одной строке, необходимо использовать ключевое слово then, чтобы CoffeeScript знал, когда начинается блок. Условные операторы (?:) не поддерживаются, вместо них следует использовать однострочный оператор if/else.
CoffeeScript: if true == true alert "We're ok"
if true != true then alert "Panic"
# Equivalent to: # (1 > 0) ? alert "Ok" : alert "Y2K!" if 1 > 0 then alert "Ok" else alert "Y2K!"
JavaScript: if (true === true) { alert("We're ok"); } if (true !== true) { alert("Panic"); }
if (1 > 0) { alert("Ok"); } else { alert("Y2K!"); }
В CoffeeScript также используется идиома Ruby, позволяющая использовать суффиксные операторы if.
CoffeeScript: alert "It's cold!" if heat < 5
JavaScript: if (heat < 5) { alert("It's cold!"); }
Вместо восклицательного знака (!) для отрицания можно также использовать ключевое слово not или оператор unless:
CoffeeScript: if not true then alert "Panic"
unless true alert "Panic"
JavaScript: if (!true) { alert("Panic"); }
Аналогично not, в CoffeeScript также вводится оператор is, который работает как === в JavaScript.
CoffeeScript: if true is 1 alert "Type coercion fail!"
JavaScript: if (true === 1) { alert("Type coercion fail!"); }
Интерполяция строк CoffeeScript поддерживает интерполяцию строк (то есть вставка значения переменной в качестве текста внутрь строки): делается это посредством использования #{} внутри строки, заключённой в двойные кавычки. На момент выхода CoffeeScript у JavaScript не было такой возможности, однако с выходом стандарта ECMAScript 6 в 2015 году возможность так делать появилась и в JavaScript: для этого строка должна заключаться в специальные кавычки `` (из символов ASCII-грависа), а вставка переменных производится с использованием ${}.
CoffeeScript: favourite_color = "Blue. No, yel..." question = "Bridgekeeper: What... is your favourite color? Galahad: #{favourite_color} Bridgekeeper: Wrong! "
JavaScript: let favouriteColor = "Blue. No, yel..."; let question = `Bridgekeeper: What... is your favourite color? Galahad: ${favouriteColor} Bridgekeeper: Wrong! `;
Массивы CoffeeScript черпает вдохновение из Ruby, когда речь идет о создании массивов с помощью диапазонов. Диапазоны создаются двумя числовыми значениями, первой и последней позициями в диапазоне, разделенными ... Если диапазон не имеет никакого префикса, CoffeeScript расширяет его до массива.
CoffeeScript: range = [1..5]
JavaScript: let range = [1, 2, 3, 4, 5];
Если же диапазон указывается сразу после переменной, то CoffeeScript преобразует его в вызов метода .slice().
CoffeeScript: firstTwo = ["one", "two", "three"][0..1]
numbers = [0..9] numbers[3..5] = [-3, -4, -5]
my = "my string"[0..2]
JavaScript: let firstTwo = ["one", "two", "three"].slice(0, 2);
let numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; numbers = [...numbers.slice(0, 3), -3, -4, -5, ...numbers.slice(6)];
let my = "my string".slice(0, 3);
Для проверки наличия значения внутри массива в JavaScript можно использовать метод .includes(). В CoffeeScript для этого есть специальный оператор in.
CoffeeScript: words = ["rattled", "roudy", "rebbles", "ranks"] alert "Stop wagging me" if "ranks" in words
JavaScript: let words = ["rattled", "roudy", "rebbles", "ranks"]; if (words.includes("ranks")) { alert("Stop wagging me"); }
Классы Ключевое слово class было добавлено в JavaScript в стандарте ECMAScript 6. При этом, JavaScript и до этого поддерживал классы (за счёт использования прототипов), а само ключевое слово class является синтаксическим сахаром:
Далее для JavaScript-кода в данном разделе будет использоваться синтаксис с использованием <code>class</code>.
CoffeeScript использует собственный прототип JavaScript для создания классов, добавляя немного синтаксического сахара для наследования статических свойств и сохранения контекста. В CoffeeScript используются функции-конструкторы, что означает возможность инстанцирования классов с помощью оператора new. CoffeeScript предоставляет сокращение для общего шаблона установки свойств экземпляра класса. Префикс аргумента @ позволяет CoffeeScript автоматически устанавливать аргументы как свойства экземпляра в конструкторе.
CoffeeScript: <source lang="coffeescript"> class Animal constructor: (@name) ->
JavaScript: class Animal { constructor(name) { this.name = name;
Свойства экземпляра Добавление дополнительных свойств экземпляра в класс очень просто, это точно такой же синтаксис, как и добавление свойств к объекту. Свойства должны быть правильно расположены с отступом внутри тела класса.
CoffeeScript: class Animal price: 5
sell: (customer) ->
animal = new Animal animal.sell(new Customer)
JavaScript: class Animal { price = 5;
sell(customer) {} }
let animal = new Animal(); animal.sell(new Customer());
Статичные свойства Внутри определения класса, ключевое слово this и @ ссылаются на объект класса.
CoffeeScript: class Animal this.find_ = (name) -> @.age_ = (age) ->
Animal.find_("Parrot")
JavaScript: class Animal { static find_(name) {} static age_(age) {} }
Animal.find_("Parrot");
Наследование Наследование класса происходит при помощи ключевого слова extends.
CoffeeScript: class Animal constructor: (@name) ->
alive: -> false
class Parrot extends Animal constructor: -> super("Parrot")
dead: -> not @alive()
JavaScript: class Animal { constructor(name) { this.name = name;
alive() { return false;
class Parrot extends Animal { constructor() { super("Parrot");
dead() { return !this.alive();
Статические свойства копируются в подклассы, а не наследуются по прототипу, как свойства экземпляра. Это связано с особенностями реализации прототипической архитектуры JavaScript и является трудноразрешимой проблемой.
Идиомы
Each В JavaScript для итерации по каждому элементу массива можно использовать метод .forEach(), либо же цикл for в стиле C. Хотя синтаксис .forEach() гораздо более лаконичен и удобен для чтения, он страдает тем недостатком, что функция обратного вызова будет вызываться на каждой итерации массива, и поэтому работает гораздо медленнее, чем эквивалентный цикл for. Синтаксис CoffeeScript обеспечивает ту же выразительность, что и .forEach(), но без ограничений по скорости.
CoffeeScript: myFunction(item) for item in array
JavaScript: // вариант с forEach array.forEach(myFunction);
// вариант с циклом for (let i = 0; i < array.length; i++) { let item = array[i]; myFunction(item); }
Includes В современном JavaScript проверка того, находится ли значение внутри массива, обычно выполняется с помощью метода .includes(). В CoffeeScript для этого можно использовать оператор in (который компилируется в метод .indexOf() JavaScript) и, при необходимости, шимминг, чтобы определить, находится ли значение внутри массива.
CoffeeScript: string = "a long test string" included = "test" in string
JavaScript: let string = "a long test string"; let included = string.includes("test");
Итерации Для итерации по объектам в JavaScript используется оператор in (для массивов обычно рекомендуется использовать оператор of). В CoffeeScript вместо этого оператор был переименован в of, и его можно использовать следующим образом:
CoffeeScript: object = {one: 1, two: 2}