CoffeeScript

CoffeeScript
Изображение логотипа
Класс языка
Появился в 13 декабря 2009
Автор Джереми Ашкенас
Расширение файлов .coffee
Выпуск 2.7.0[1]
Испытал влияние JavaScript, Python, Ruby, Haskell, Erlang
Повлиял на MoonScript, LiveScript
Лицензия лицензия MIT[2]
Сайт coffeescript.org
ОС кроссплатформенность

CoffeeScript — язык программирования, транспилируемый в JavaScript. CoffeeScript добавляет синтаксический сахар в духе Ruby, Python, Haskell и Erlang для того, чтобы улучшить читаемость кода и уменьшить его размер. CoffeeScript позволяет писать более компактный код по сравнению с JavaScript[3]. 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 не является широко используемым, из-за чего сложнее искать источники информации по нему и кооперировать с другими разработчиками

Синтаксис

Особенности

  1. отсутствие точек с запятой (при этом, в самом JavaScript использование точек с запятой не обязательно, хоть и рекомендуется)
  2. фигурные скобки {} заменены табуляцией

Комментарии

В 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 является синтаксическим сахаром:

class Person {
  constructor(name) {
    this.name = name;
  }
  
  say(phrase) {
    return `${this.name} говорит ${phrase}`;
  }
}

// Данный код полностью эквивалентен следующему коду:

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

Person.prototype.say = function(phrase) {
  return this.name + " говорит " + phrase;
}

Далее для JavaScript-кода в данном разделе будет использоваться синтаксис с использованием class.

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

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}
alert("#{key} = #{value}") for key, value of object

JavaScript:

let object = {
  one: 1,
  two: 2
};

for (let key in object) {
  let value = object[key];
  alert(`${key} = ${value}`);
}

min и max

Math.max и Math.min принимают несколько аргументов, поэтому можно легко использовать для передачи им массива, получая максимальное и минимальное значения в массиве.

CoffeeScript:

Math.max [14, 35, -7, 46, 98]... # 98
Math.min [14, 35, -7, 46, 98]... # -7

JavaScript:

// два эквивалентных по результату способа; первый:
Math.max(...[14, 35, -7, 46, 98]);
Math.min(...[14, 35, -7, 46, 98]);
// (здесь используется оператор ..., позволяющий разбивать массивы на отдельные значения и напрямую передавать их в функции как параметры)

// второй способ:
Math.max.apply(null, [14, 35, -7, 46, 98]);
Math.min.apply(null, [14, 35, -7, 46, 98]);

And/or

В руководствах по стилю CoffeeScript указано, что or предпочтительнее, чем ||, а and предпочтительнее, чем &&. Это предпочтение более английского стиля также относится к использованию is вместо == и isnt вместо !=.

CoffeeScript:

string = "migrating coconuts"
string == string # true
string is string # true

JavaScript:

let string = "migrating coconuts";
string === string;
string === string;

Внешние библиотеки

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

CoffeeScript:

# Use local alias
$ = jQuery

$ ->
  # DOMContentLoaded
  $(".el").click ->
    alert("Clicked!")

JavaScript:

let $ = jQuery;

$(function() {
  return $(".el").click(function() {
    return alert("Clicked!");
  });
});

Локальные переменные

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

Реализация

На официальном сайте языка есть раздел «try coffeescript», позволяющий выполнять программы на нём online[4]. В отличие, к примеру, от Try Ruby[5], при этом не будет происходить запросов к серверу, код компилируется и исполняется непосредственно в браузере.

Примеры

Переменные

CoffeeScript:

age = 2
male = true
name = "Матвей"

JavaScript:

let age = 2,
    male = true,
    name = "Матвей";

Функции

CoffeeScript:

say = (speech) ->
  alert speech

say "Привет мир!"

JavaScript:

const say = speech =>
  alert(speech);

say('Привет мир!');

Классы и объекты

CoffeeScript:

class Human
  constructor: (@name) ->

class Baby extends Human
  say: (msg) -> alert "#{@name} говорит '#{msg}'"
  sayHi: -> @say('здравствуй!')

matt = new Baby("Матвей")
matt.sayHi()

JavaScript:

class Human {
  constructor(name) {
    this.name = name;
  }
}

class Baby extends Human {
  say(msg) {
	alert(`${this.name} говорит '${msg}'`);
  }
  sayHi()	{
    this.say('здравствуй!');
  }
}

let matt = new Baby('Матвей');
matt.sayHi();

Аналог на JavaScript (именно аналог, а не результат компиляции):

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

function Baby(name){
  Human.call(this, name);
}

Baby.prototype = Object.create(Human.prototype);
Baby.prototype.say = function(msg){
  alert(this.name + ' говорит ' + msg);
};
Baby.prototype.sayHi = function(){
  this.say('здравствуй!');
};
Baby.prototype.constructor = Human;

var matt = new Baby("Матвей");
matt.sayHi();


Пример класса CoffeeScript с различными видами свойств.

class Test
  say = (msg) -> alert msg       # приватный метод
  @echo = (msg) -> console.log msg # статический метод, записан в Test
  setHi: (msg) ->                 # динамический метод, записан в Test.prototype
    @hi = -> msg                   # динамический метод, записан в экземпляр Test

Компилятор

Интересным является тот факт, что компилятор для CoffeeScript написан на самом CoffeeScript

См. также

Примечания

  1. 2.7.0. Архивировано 23 июня 2022. Дата обращения: 23 июня 2022.
  2. The coffeescript Open Source Project on Open Hub: Licenses Page — 2006.
  3. Пример на титульной странице официального сайта. Дата обращения: 18 января 2012. Архивировано 9 июня 2017 года.
  4. Try CoffeeScript. coffeescript.org. Дата обращения: 4 января 2016. Архивировано 9 июня 2017 года.
  5. Try Ruby: learn the basics of the Ruby language in your browser. tryruby.org. Дата обращения: 4 января 2016. Архивировано 28 сентября 2011 года.

Литература

Ссылки

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.