Spec-Zone.ru › CoffeeScript 1

CoffeeScript

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

Золотое правило CoffeeScript: «Это просто JavaScript». Код компилируется один к одному в эквивалентный JS, и во время выполнения нет интерпретации. Вы можете использовать любые существующие JavaScript-библиотеки беспрепятственно из CoffeeScript (и наоборот). Скомпилированный результат читабелен, отформатирован красиво и, как правило, выполняется так же быстро, или быстрее, чем эквивалентный написанный вручную JavaScript.

Компилятор CoffeeScript прилагает все усилия для генерации выходного JavaScript, который работает в любой среде JavaScript, но есть исключения. Используйте генераторные функции, for…from или меченные шаблоны строк только если вы знаете, что ваши целевые среды выполнения поддерживают их. Если вы используете модули, вам нужно будет использовать дополнительный инструмент для их разрешения.

Последняя версия 1.x: 1.12.7

npm install -g coffeescript

Обновитесь до CoffeeScript 2! Он добавляет поддержку классов ES2015, async/await, JSX, синтаксиса rest/spread для объектов и JavaScript, сгенерированного с использованием современного синтаксиса. Узнайте больше.

Обзор

CoffeeScript слева, скомпилированный JavaScript справа.

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?

# Array comprehensions:
cubes = (math.cube num for num in list)
var cubes, list, math, num, number, opposite, race, square,
  slice = [].slice;

number = 42;

opposite = true;

if (opposite) {
  number = -42;
}

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

list = [1, 2, 3, 4, 5];

math = {
  root: Math.sqrt,
  square: square,
  cube: function(x) {
    return x * square(x);
  }
};

race = function() {
  var runners, winner;
  winner = arguments[0], runners = 2 <= arguments.length ? slice.call(arguments, 1) : [];
  return print(winner, runners);
};

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

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

Установка

Командная версия coffee доступна как утилита Node.js. Однако, основной компилятор ядра компилятора не зависит от Node и может работать в любой JavaScript-среде или в браузере (см. Попробовать CoffeeScript).

Для установки убедитесь, что у вас есть рабочая копия последней стабильной версии Node.js. Затем вы можете установить CoffeeScript глобально с помощью npm:

npm install --global coffeescript

Это сделает команды coffee и cake доступными глобально.

Когда вам нужен CoffeeScript как зависимость проекта, внутри папки этого проекта вы можете установить его локально:

npm install --save coffeescript

Команды coffee и cake сначала проверят текущую папку, чтобы увидеть, установлен ли CoffeeScript локально, и будут использовать эту версию, если это так. Это позволяет устанавливать разные версии CoffeeScript глобально и локально.

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

После установки у вас должен быть доступ к команде coffee, которая может запускать скрипты, компилировать .coffee файлы в .js, и предоставлять интерактивный REPL. Команда coffee принимает следующие параметры:

Параметр Описание
-c, --compile Компилирует .coffee скрипт в .js JavaScript-файл с тем же именем.
-m, --map Генерирует карты исходных кодов вместе со скомпилированными JavaScript-файлами. Также добавляет директивы sourceMappingURL в JavaScript.
-M, --inline-map То же, что и --map, но включает карту исходных кодов непосредственно в скомпилированные JavaScript-файлы, а не в отдельный файл.
-i, --interactive Запускает интерактивную сессию CoffeeScript для пробных коротких фрагментов. Идентично вызову coffee без аргументов.
-o, --output [DIR] Выводит все скомпилированные JavaScript-файлы в указанную директорию. Используйте в сочетании с --compile или --watch.
-w, --watch Следит за изменениями файлов, повторно выполняя указанную команду при обновлении любого файла.
-p, --print Вместо записи JavaScript в файл, выводит его напрямую в stdout.
-s, --stdio Передает CoffeeScript в STDIN и получает JavaScript на STDOUT. Хорошо подходит для использования с процессами, написанными на других языках. Пример:
cat src/cake.coffee | coffee -sc
-l, --literate Парсит код как Literate CoffeeScript. Вам нужно указать это только при передаче кода непосредственно через stdio или при использовании имени файла без расширения.
-e, --eval Компилирует и выводит небольшой фрагмент CoffeeScript непосредственно из командной строки. Например:
coffee -e "console.log num for num in [10..1]"
-r, --require [MODULE] require() указанный модуль перед запуском REPL или оценкой кода, переданного с флагом --eval.
-b, --bare Компилирует JavaScript без обертки безопасности функции верхнего уровня top-level function safety wrapper.
-t, --tokens Вместо парсинга CoffeeScript, просто лексически разберёт его и выведет поток токенов. Используется для отладки компилятора.
-n, --nodes Вместо компиляции CoffeeScript, просто лексически разберёт его, парсит и выведет дерево разбора. Используется для отладки компилятора.
--nodejs Исполняемый файл node имеет несколько полезных параметров, которые вы можете установить, такие как --debug, --debug-brk, --max-stack-size, и --expose-gc. Используйте этот флаг для передачи параметров непосредственно в Node.js. Для передачи нескольких флагов используйте --nodejs несколько раз.
--no-header Отключить заголовок «Сгенерировано CoffeeScript».

Примеры:

  • Компилировать дерево каталогов файлов .coffee в src в параллельное дерево файлов .js в lib:
    coffee --compile --output lib/ src/
  • Наблюдать за изменениями в файле и перекомпилировать его каждый раз, когда файл сохраняется:
    coffee --watch --compile experimental.coffee
  • Конкатенация списка файлов в один скрипт:
    coffee --join project.js --compile src/*.coffee
  • Вывод скомпилированного JS из однострочника:
    coffee -bpe "alert i for i in [0..10]"
  • Вместе, наблюдайте за изменениями и перекомпилируйте весь проект по мере работы:
    coffee -o lib/ -cw src/
  • Запустить CoffeeScript REPL (Ctrl-D для выхода, Ctrl-V для многострочного):
    coffee

Literate CoffeeScript

Помимо использования в качестве обычного языка программирования, CoffeeScript также может быть написан в «описательном» режиме. Если вы назовёте свой файл с расширением .litcoffee, вы можете написать его как документ Markdown — документ, который также является исполняемым кодом CoffeeScript. Компилятор будет рассматривать все отступы (способ Markdown обозначить исходный код) как код и игнорировать остальное как комментарии.

Просто для примера, часть компилятора в настоящее время реализована таким образом: Просмотреть её как документ, сырой и правильно выделенный в текстовом редакторе.

Справочник языка

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

Многие примеры можно запустить (где это уместно), нажав кнопку «запуск» справа, и можно загрузить в консоль «Попробовать CoffeeScript», нажав кнопку «загрузить» слева.

Прежде всего, основы: CoffeeScript использует значительные отступы для разграничения блоков кода. Вам не нужно использовать точки с запятой ; для завершения выражений, достаточно закончить строку (хотя точки с запятой по-прежнему могут использоваться для размещения нескольких выражений в одной строке). Вместо использования фигурных скобок { } для окружения блоков кода в функциях, условных операторах if, switch и try/catch, используйте отступы.

Вам не нужно использовать скобки для вызова функции, если вы передаёте аргументы. Неявный вызов распространяется до конца строки или выражения блока.
console.log sys.inspect object → console.log(sys.inspect(object));

Функции

Функции определяются с помощью необязательного списка параметров в скобках, стрелки и тела функции. Пустая функция выглядит так: ->

square = (x) -> x * x
cube   = (x) -> square(x) * x
var cube, square;

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

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

Функции также могут иметь значения по умолчанию для аргументов, которые будут использоваться, если входящий аргумент отсутствует (null или undefined).

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 + "...";
};

Объекты и массивы

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

song = ["do", "re", "mi", "fa", "so"]

singers = {Jagger: "Rock", Elvis: "Roll"}

bitlist = [
  1, 0, 1
  0, 0, 1
  1, 1, 0
]

kids =
  brother:
    name: "Max"
    age:  11
  sister:
    name: "Ida"
    age:  9
var bitlist, kids, singers, song;

song = ["do", "re", "mi", "fa", "so"];

singers = {
  Jagger: "Rock",
  Elvis: "Roll"
};

bitlist = [1, 0, 1, 0, 0, 1, 1, 1, 0];

kids = {
  brother: {
    name: "Max",
    age: 11
  },
  sister: {
    name: "Ida",
    age: 9
  }
};

В JavaScript нельзя использовать зарезервированные слова, такие как class, в качестве свойств объекта без их заключения в строковые кавычки. CoffeeScript распознаёт зарезервированные слова, используемые в качестве ключей в объектах, и заключает их в кавычки для вас, поэтому вам об этом не нужно беспокоиться (например, при использовании jQuery).

$('.account').attr class: 'active'

log object.class
$('.account').attr({
  "class": 'active'
});

log(object["class"]);

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

name = "Michelangelo"
mask = "orange"
weapon = "nunchuks"
turtle = {name, mask, weapon}
output = "#{turtle.name} wears an #{turtle.mask} mask. Watch out for his #{turtle.weapon}!"
var mask, name, output, turtle, weapon;

name = "Michelangelo";

mask = "orange";

weapon = "nunchuks";

turtle = {
  name: name,
  mask: mask,
  weapon: weapon
};

output = turtle.name + " wears an " + turtle.mask + " mask. Watch out for his " + turtle.weapon + "!";

Лексическая область видимости и безопасность переменных

Компилятор CoffeeScript заботится о том, чтобы все ваши переменные были должным образом объявлены в лексической области видимости — вам никогда не нужно писать var самостоятельно.

outer = 1
changeNumbers = ->
  inner = -1
  outer = 10
inner = changeNumbers()
var changeNumbers, inner, outer;

outer = 1;

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

inner = changeNumbers();

Обратите внимание, как все объявления переменных были вынесены в начало ближайшей области видимости, в первый раз, когда они появляются. outer не переобъявляется внутри внутренней функции, потому что она уже в области видимости; inner внутри функции, с другой стороны, не должна изменять значение внешней переменной с тем же именем, и поэтому имеет собственное объявление.

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

Хотя в данном документе для ясности подавлены, весь CoffeeScript-вывод заключен в анонимную функцию: (function(){ … })(); Этот защитный обертка, в сочетании с автоматическим генерированием ключевого слова var, делает чрезвычайно затруднительным случайное загрязнение глобального пространства имён.

Если вы хотите создать переменные верхнего уровня для использования другими скриптами, прикрепите их как свойства к window; прикрепите их как свойства к объекту exports в CommonJS; или используйте оператор export. Если вы нацелены на CommonJS и браузер, оператор существования (описанный ниже) даёт надёжный способ выяснить, куда их добавить: exports ? this

Условные операторы: if, else, unless и присваивание по условию

Операторы if/else могут быть написаны без использования круглых скобок и фигурных скобок. Как и функции и другие выражения блоков, многострочные условные операторы разделяются отступами. Также есть удобная постфиксная форма с if или unless в конце.

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

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 && knowsIt) {
  clapsHands();
  chaChaCha();
} else {
  showIt();
}

date = friday ? sue : jill;

Размывы…

JavaScript-объект arguments — полезный способ работы с функциями, принимающими переменное количество аргументов. CoffeeScript предоставляет размывы ..., как для определения функции, так и для вызова, что делает переменное число аргументов немного более приемлемым.

gold = silver = rest = "unknown"

awardMedals = (first, second, others...) ->
  gold   = first
  silver = second
  rest   = others

contenders = [
  "Michael Phelps"
  "Liu Xiang"
  "Yao Ming"
  "Allyson Felix"
  "Shawn Johnson"
  "Roman Sebrle"
  "Guo Jingjing"
  "Tyson Gay"
  "Asafa Powell"
  "Usain Bolt"
]

awardMedals contenders...

alert "Gold: " + gold
alert "Silver: " + silver
alert "The Field: " + rest
var awardMedals, contenders, gold, rest, silver,
  slice = [].slice;

gold = silver = rest = "unknown";

awardMedals = function() {
  var first, others, second;
  first = arguments[0], second = arguments[1], others = 3 <= arguments.length ? slice.call(arguments, 2) : [];
  gold = first;
  silver = second;
  return rest = others;
};

contenders = ["Michael Phelps", "Liu Xiang", "Yao Ming", "Allyson Felix", "Shawn Johnson", "Roman Sebrle", "Guo Jingjing", "Tyson Gay", "Asafa Powell", "Usain Bolt"];

awardMedals.apply(null, contenders);

alert("Gold: " + gold);

alert("Silver: " + silver);

alert("The Field: " + rest);

Циклы и выражения-сжатия

Большинство циклов, которые вы будете писать в CoffeeScript, будут выражениями-сжатия над массивами, объектами и диапазонами. Выражения-сжатия заменяют (и компилируются в) циклы for, с опциональными условиями и значением текущего индекса массива. В отличие от циклов for, выражения-сжатия для массивов являются выражениями и могут быть возвращаемы и присваиваться.

# Eat lunch.
eat food for food in ['toast', 'cheese', 'wine']

# Fine five course dining.
courses = ['greens', 'caviar', 'truffles', 'roast', 'cake']
menu i + 1, dish for dish, i in courses

# Health conscious meal.
foods = ['broccoli', 'spinach', 'chocolate']
eat food for food in foods when food isnt 'chocolate'
var courses, dish, food, foods, i, j, k, l, len, len1, len2, ref;

ref = ['toast', 'cheese', 'wine'];
for (j = 0, len = ref.length; j < len; j++) {
  food = ref[j];
  eat(food);
}

courses = ['greens', 'caviar', 'truffles', 'roast', 'cake'];

for (i = k = 0, len1 = courses.length; k < len1; i = ++k) {
  dish = courses[i];
  menu(i + 1, dish);
}

foods = ['broccoli', 'spinach', 'chocolate'];

for (l = 0, len2 = foods.length; l < len2; l++) {
  food = foods[l];
  if (food !== 'chocolate') {
    eat(food);
  }
}

Выражения-сжатия должны быть способны обрабатывать большинство мест, где вы в противном случае использовали цикл, each/forEach, map или select/filter, например:
shortNames = (name for name in list when name.length < 5)
Если вы знаете начало и конец вашего цикла или хотите переходить через него с фиксированным шагом, вы можете использовать диапазон для указания начала и конца вашего выражения-сжатия.

countdown = (num for num in [10..1])
var countdown, num;

countdown = (function() {
  var i, results;
  results = [];
  for (num = i = 10; i >= 1; num = --i) {
    results.push(num);
  }
  return results;
})();

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

Чтобы переходить по диапазону выражения-сжатия с фиксированным шагом, используйте by, например: evens = (x for x in [0..10] by 2)

Если вам не нужно текущее значение итерации, вы можете его опустить: browser.closeCurrentTab() for [0...count]

Выражения-сжатия также могут использоваться для итерации по ключам и значениям в объекте. Используйте of для обозначения выражения-сжатия над свойствами объекта вместо значений в массиве.

yearsOld = max: 10, ida: 9, tim: 11

ages = for child, age of yearsOld
  "#{child} is #{age}"
var age, ages, child, yearsOld;

yearsOld = {
  max: 10,
  ida: 9,
  tim: 11
};

ages = (function() {
  var results;
  results = [];
  for (child in yearsOld) {
    age = yearsOld[child];
    results.push(child + " is " + age);
  }
  return results;
})();

Если вы хотите итерироваться только по ключам, определённым в самом объекте, добавив hasOwnProperty проверку, чтобы избежать свойств, которые могут быть унаследованы от прототипа, используйте for own key, value of object.

Для итерации по генератору функций используйте from. См. Генераторные функции.

Единственный низкоуровневый цикл, который предоставляет CoffeeScript, — это цикл while. Основное отличие от JavaScript заключается в том, что цикл while может использоваться как выражение, возвращающее массив, содержащий результат каждой итерации цикла.

# Econ 101
if this.studyingEconomics
  buy()  while supply > demand
  sell() until supply > demand

# Nursery Rhyme
num = 6
lyrics = while num -= 1
  "#{num} little monkeys, jumping on the bed.
    One fell out and bumped his head."
var lyrics, num;

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

num = 6;

lyrics = (function() {
  var results;
  results = [];
  while (num -= 1) {
    results.push(num + " little monkeys, jumping on the bed. One fell out and bumped his head.");
  }
  return results;
})();

Для удобочитаемости, ключевое слово until эквивалентно while not, а ключевое слово loop эквивалентно while true.

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

for filename in list
  do (filename) ->
    fs.readFile filename, (err, contents) ->
      compile filename, contents.toString()
var filename, fn, i, len;

fn = function(filename) {
  return fs.readFile(filename, function(err, contents) {
    return compile(filename, contents.toString());
  });
};
for (i = 0, len = list.length; i < len; i++) {
  filename = list[i];
  fn(filename);
}

Выделение и вставка фрагментов массивов с помощью диапазонов

Диапазоны также могут использоваться для выделения фрагментов массивов. С двумя точками (3..6), диапазон включительно (3, 4, 5, 6); с тремя точками (3...6), диапазон исключает конец (3, 4, 5). Индексы срезов имеют полезные значения по умолчанию. Пропущенный первый индекс по умолчанию равен нулю, а пропущенный второй индекс по умолчанию равен размеру массива.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]

start   = numbers[0..2]

middle  = numbers[3...-2]

end     = numbers[-2..]

copy    = numbers[..]
var copy, end, middle, numbers, start;

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9];

start = numbers.slice(0, 3);

middle = numbers.slice(3, -2);

end = numbers.slice(-2);

copy = numbers.slice(0);

Такая же синтаксическая конструкция может быть использована с присваиванием, чтобы заменить часть массива новыми значениями, вставляя их.

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

numbers[3..6] = [-3, -4, -5, -6]
var numbers, ref;

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

[].splice.apply(numbers, [3, 4].concat(ref = [-3, -4, -5, -6])), ref;

Обратите внимание, что JavaScript-строки неизменяемы и не могут быть вставлены.

Всё — выражение (по крайней мере, насколько это возможно)

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

grade = (student) ->
  if student.excellentWork
    "A+"
  else if student.okayStuff
    if student.triedHard then "B" else "B-"
  else
    "C"

eldest = if 24 > 21 then "Liz" else "Ike"
var eldest, grade;

grade = function(student) {
  if (student.excellentWork) {
    return "A+";
  } else if (student.okayStuff) {
    if (student.triedHard) {
      return "B";
    } else {
      return "B-";
    }
  } else {
    return "C";
  }
};

eldest = 24 > 21 ? "Liz" : "Ike";

Хотя функции всегда возвращают своё конечное значение, вполне возможно и рекомендуется возвращать из функции пораньше, используя явное возвращение (return value), когда вы понимаете, что закончили.

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

six = (one = 1) + (two = 2) + (three = 3)
var one, six, three, two;

six = (one = 1) + (two = 2) + (three = 3);

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

# The first ten global properties.

globals = (name for name of window)[0...10]
var globals, name;

globals = ((function() {
  var results;
  results = [];
  for (name in window) {
    results.push(name);
  }
  return results;
})()).slice(0, 10);

А также глупые вещи, например, передача оператора try/catch непосредственно в вызов функции:

alert(
  try
    nonexistent / undefined
  catch error
    "And the error is ... #{error}"
)
var error;

alert((function() {
  try {
    return nonexistent / void 0;
  } catch (error1) {
    error = error1;
    return "And the error is ... " + error;
  }
})());

Существует несколько операторов в JavaScript, которые не могут быть осмысленно преобразованы в выражения, а именно break, continue, и return. Если вы их используете внутри блока кода, CoffeeScript не будет пытаться выполнить преобразование.

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

Так как оператор == часто приводит к нежелательному преобразованию типов, не транзитивен и имеет другое значение, чем в других языках, CoffeeScript компилирует == в ===, и != в !==. Кроме того, is компилируется в ===, а isnt в !==.

Вы можете использовать not как псевдоним для !.

Для логических операторов, and компилируется в &&, а or в ||.

Вместо новой строки или точки с запятой, then может использоваться для разделения условий от выражений в операторах while, if/else и switch/when.

Как в YAML, on и yes эквивалентны булевым true, в то время как off и no являются булевыми false.

unless может быть использован как обратный оператор для if.

В качестве сокращения для this.property, можно использовать @property.

Вы можете использовать in для проверки наличия массива и of для проверки наличия ключа в JavaScript-объекте.

Для упрощения математических выражений, ** может использоваться для возведения в степень, а // выполняет целочисленное деление. % работает так же, как и в JavaScript, а %% обеспечивает “зависимый от делимого остаток от деления”:

-7 % 5 == -2 # The remainder of 7 / 5
-7 %% 5 == 3 # n %% 5 is always between 0 and 4

tabs.selectTabAtIndex((tabs.currentIndex - count) %% tabs.length)
var modulo = function(a, b) { return (+a % (b = +b) + b) % b; };

-7 % 5 === -2;

modulo(-7, 5) === 3;

tabs.selectTabAtIndex(modulo(tabs.currentIndex - count, tabs.length));

Всё вместе:

CoffeeScript JavaScript
is ===
isnt !==
not !
and &&
or ||
true, yes, on true
false, no, off false
@, this this
of in
in аналогичного JavaScript-оператора нет
a ** b Math.pow(a, b)
a // b Math.floor(a / b)
a %% b (a % b + b) % b
launch() if ignition is on

volume = 10 if band isnt SpinalTap

letTheWildRumpusBegin() unless answer is no

if car.speed < limit then accelerate()

winner = yes if pick in [47, 92, 13]

print inspect "My name is #{@name}"
var volume, winner;

if (ignition === true) {
  launch();
}

if (band !== SpinalTap) {
  volume = 10;
}

if (answer !== false) {
  letTheWildRumpusBegin();
}

if (car.speed < limit) {
  accelerate();
}

if (pick === 47 || pick === 92 || pick === 13) {
  winner = true;
}

print(inspect("My name is " + this.name));

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

В JavaScript довольно сложно проверить существование переменной. if (variable) … близко к этому, но не работает для нуля, пустой строки и ложного значения. Оператор существования CoffeeScript ? возвращает true, если переменная не null и не undefined, что делает его аналогичным Ruby-оператору nil?

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

solipsism = true if mind? and not world?

speed = 0
speed ?= 15

footprints = yeti ? "bear"
var footprints, solipsism, speed;

if ((typeof mind !== "undefined" && mind !== null) && (typeof world === "undefined" || world === null)) {
  solipsism = true;
}

speed = 0;

if (speed == null) {
  speed = 15;
}

footprints = typeof yeti !== "undefined" && yeti !== null ? yeti : "bear";

Доступная версия оператора существования ?. может использоваться для обработки нулевых ссылок в цепочке свойств. Используйте её вместо оператора точки . в тех случаях, когда базовое значение может быть null или undefined. Если все свойства существуют, вы получите ожидаемый результат, если цепочка прервётся, будет возвращено undefined вместо TypeError, который бы возник в противном случае.

zip = lottery.drawWinner?().address?.zipcode
var ref, zip;

zip = typeof lottery.drawWinner === "function" ? (ref = lottery.drawWinner().address) != null ? ref.zipcode : void 0 : void 0;

Игнорирование нулевых значений аналогично драгоценному камню Ruby andand и оператору безопасной навигации Groovy .

Классы, Наследование и Супер

Прототипное наследование JavaScript всегда было немного сложным для понимания, с целым семейством библиотек, которые предоставляют более чистый синтаксис для классического наследования поверх прототипов JavaScript: Base2, Prototype.js, JS.Class и т. д. Библиотеки предоставляют синтаксический сахар, но встроенное наследование было бы полностью применимо, если бы не было нескольких небольших исключений: неудобно вызывать super (реализацию прототипа объекта текущей функции), и неудобно правильно установить цепочку прототипов.

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

Функции конструкторов имеют имена, чтобы лучше поддерживать полезные трассировки стека. В первом классе в примере ниже, this.constructor.name is "Animal".

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()
var Animal, Horse, Snake, sam, tom,
  extend = 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; },
  hasProp = {}.hasOwnProperty;

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

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

  return Animal;

})();

Snake = (function(superClass) {
  extend(Snake, superClass);

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

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

  return Snake;

})(Animal);

Horse = (function(superClass) {
  extend(Horse, superClass);

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

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

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

String::dasherize = ->
  this.replace /_/g, "-"
String.prototype.dasherize = function() {
  return this.replace(/_/g, "-");
};

Наконец, определения классов — это блоки исполняемого кода, которые открывают интересные возможности метапрограммирования. Поскольку в контексте определения класса this — это сам объект класса (функция-конструктор), вы можете назначить статические свойства, используя @property: value, и вызывать функции, определённые в родительских классах: @attr 'title', type: 'text'.

Распределённое присваивание

Как и в JavaScript (с ES2015), CoffeeScript имеет синтаксис распределённого присваивания. Когда вы присваиваете массив или объект-литерал значению, CoffeeScript разбивает и сопоставляет обе стороны друг с другом, присваивая значения справа переменным слева. В простейшем случае он может использоваться для параллельного присваивания:

theBait   = 1000
theSwitch = 0

[theBait, theSwitch] = [theSwitch, theBait]
var ref, theBait, theSwitch;

theBait = 1000;

theSwitch = 0;

ref = [theSwitch, theBait], theBait = ref[0], theSwitch = ref[1];

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

weatherReport = (location) ->
  # Make an Ajax request to fetch the weather...
  [location, 72, "Mostly Sunny"]

[city, temp, forecast] = weatherReport "Berkeley, CA"
var city, forecast, ref, temp, weatherReport;

weatherReport = function(location) {
  return [location, 72, "Mostly Sunny"];
};

ref = weatherReport("Berkeley, CA"), city = ref[0], temp = ref[1], forecast = ref[2];

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

futurists =
  sculptor: "Umberto Boccioni"
  painter:  "Vladimir Burliuk"
  poet:
    name:   "F.T. Marinetti"
    address: [
      "Via Roma 42R"
      "Bellagio, Italy 22021"
    ]

{sculptor} = futurists

{poet: {name, address: [street, city]}} = futurists
var city, futurists, name, ref, ref1, sculptor, street;

futurists = {
  sculptor: "Umberto Boccioni",
  painter: "Vladimir Burliuk",
  poet: {
    name: "F.T. Marinetti",
    address: ["Via Roma 42R", "Bellagio, Italy 22021"]
  }
};

sculptor = futurists.sculptor;

ref = futurists.poet, name = ref.name, (ref1 = ref.address, street = ref1[0], city = ref1[1]);

Распределённое присваивание можно даже комбинировать со спанч-операторами.

tag = "<impossible>"

[open, contents..., close] = tag.split("")
var close, contents, i, open, ref, tag,
  slice = [].slice;

tag = "<impossible>";

ref = tag.split(""), open = ref[0], contents = 3 <= ref.length ? slice.call(ref, 1, i = ref.length - 1) : (i = 1, []), close = ref[i++];

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

text = "Every literary critic believes he will
        outwit history and have the last word"

[first, ..., last] = text.split " "
var first, last, ref, text;

text = "Every literary critic believes he will outwit history and have the last word";

ref = text.split(" "), first = ref[0], last = ref[ref.length - 1];

Распределённое присваивание также полезно при комбинировании с конструкторами классов для присваивания свойств экземпляру из объекта опций, переданного конструктору.

class Person
  constructor: (options) ->
    {@name, @age, @height = 'average'} = options

tim = new Person name: 'Tim', age: 4
var Person, tim;

Person = (function() {
  function Person(options) {
    var ref;
    this.name = options.name, this.age = options.age, this.height = (ref = options.height) != null ? ref : 'average';
  }

  return Person;

})();

tim = new Person({
  name: 'Tim',
  age: 4
});

Вышеприведённый пример также демонстрирует, что если свойства отсутствуют в деструктурированном объекте или массиве, вы можете, как и в JavaScript, предоставить значения по умолчанию. Разница с JavaScript заключается в том, что CoffeeScript, как всегда, одинаково обрабатывает как null, так и undefined.

Связанные функции, функции-генераторы

В JavaScript ключевое слово this динамически относится к объекту, к которому прикреплена текущая функция. Если вы передаёте функцию как обратный вызов или прикрепляете её к другому объекту, исходное значение this будет утеряно. Если вы не знакомы с этим поведением, статья Digital Web даёт хорошее представление о его особенностях.

Стрелочный оператор => может использоваться как для определения функции, так и для связывания её с текущим значением this, прямо на месте. Это полезно при использовании библиотек, основанных на обратных вызовах, таких как Prototype или jQuery, для создания функций-итераторов для передачи в each или функций-обработчиков событий для использования с on. Функции, созданные с помощью стрелочного оператора, могут получить доступ к свойствам this там, где они определены.

Account = (customer, cart) ->
  @customer = customer
  @cart = cart

  $('.shopping_cart').on 'click', (event) =>
    @customer.purchase @cart
var Account;

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

Если бы мы использовали -> в обратном вызове выше, @customer ссылался бы на неопределённое свойство «customer» элемента DOM, а попытка вызвать purchase() на нём привела бы к исключению.

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

Функции CoffeeScript также поддерживают функции-генераторы ES2015 с помощью ключевого слова yield. Нет function*(){} ненужного бреда — генератор в CoffeeScript — это просто функция, которая возвращает значение.

perfectSquares = ->
  num = 0
  loop
    num += 1
    yield num * num
  return

window.ps or= perfectSquares()
var perfectSquares;

perfectSquares = function*() {
  var num;
  num = 0;
  while (true) {
    num += 1;
    yield num * num;
  }
};

window.ps || (window.ps = perfectSquares());

yield* называется yield from, и yield return может быть использовано, если вам нужно принудительно использовать генератор, который не возвращает значение.

Итерировать по функции-генератору можно с помощью for…from.

fibonacci = ->
  [previous, current] = [1, 1]
  loop
    [previous, current] = [current, previous + current]
    yield current
  return

getFibonacciNumbers = (length) ->
  results = [1]
  for n from fibonacci()
    results.push n
    break if results.length is length
  results
var fibonacci, getFibonacciNumbers;

fibonacci = function*() {
  var current, previous, ref, ref1;
  ref = [1, 1], previous = ref[0], current = ref[1];
  while (true) {
    ref1 = [current, previous + current], previous = ref1[0], current = ref1[1];
    yield current;
  }
};

getFibonacciNumbers = function(length) {
  var n, ref, results;
  results = [1];
  ref = fibonacci();
  for (n of ref) {
    results.push(n);
    if (results.length === length) {
      break;
    }
  }
  return results;
};

Встроенный JavaScript

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

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

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

Обратные кавычки экранируются с помощью обратных слэшей: \`​ становится `​.

Обратные слэши перед обратными кавычками экранируются с помощью дополнительных обратных слэшей: \\\`​ становится \`​.

markdown = `function () {
  return \`In Markdown, write code like \\\`this\\\`\`;
}`
var markdown;

markdown = function () {
  return `In Markdown, write code like \`this\``;
};

Вы также можете встраивать блоки JavaScript с помощью тройных обратных кавычек. Это проще, чем экранировать обратные кавычки, если вам нужно их использовать внутри блока JavaScript.

```
function time() {
  return `The time is ${new Date().toLocaleTimeString()}`;
}
```
function time() {
  return `The time is ${new Date().toLocaleTimeString()}`;
}
;

Switch/When/Else

Операторы Switch в JavaScript немного неуклюжи. Вам нужно помнить, что нужно использовать break в конце каждого оператора case, чтобы избежать случайного перехода к оператору default. CoffeeScript предотвращает случайный переход, и может преобразовать switch в возвращаемое, присваиваемое выражение. Формат: switch условие, when пункты, else пункт по умолчанию.

Как и в Ruby, операторы switch в CoffeeScript могут принимать несколько значений для каждого пункта when. Если совпадает любое из значений, выполняется пункт.

switch day
  when "Mon" then go work
  when "Tue" then go relax
  when "Thu" then go iceFishing
  when "Fri", "Sat"
    if day is bingoDay
      go bingo
      go dancing
  when "Sun" then go church
  else go work
switch (day) {
  case "Mon":
    go(work);
    break;
  case "Tue":
    go(relax);
    break;
  case "Thu":
    go(iceFishing);
    break;
  case "Fri":
  case "Sat":
    if (day === bingoDay) {
      go(bingo);
      go(dancing);
    }
    break;
  case "Sun":
    go(church);
    break;
  default:
    go(work);
}

Операторы Switch также могут использоваться без выражения управления, превращая их в более чистую альтернативу цепочке if/else.

score = 76
grade = switch
  when score < 60 then 'F'
  when score < 70 then 'D'
  when score < 80 then 'C'
  when score < 90 then 'B'
  else 'A'
# grade == 'C'
var grade, score;

score = 76;

grade = (function() {
  switch (false) {
    case !(score < 60):
      return 'F';
    case !(score < 70):
      return 'D';
    case !(score < 80):
      return 'C';
    case !(score < 90):
      return 'B';
    default:
      return 'A';
  }
})();

Try/Catch/Finally

Try-выражения имеют те же семантику, что и try-операторы в JavaScript, хотя в CoffeeScript вы можете опустить обе части catch и finally. Часть catch также может опустить параметр ошибки, если он не нужен.

try
  allHellBreaksLoose()
  catsAndDogsLivingTogether()
catch error
  print error
finally
  cleanUp()
var error;

try {
  allHellBreaksLoose();
  catsAndDogsLivingTogether();
} catch (error1) {
  error = error1;
  print(error);
} finally {
  cleanUp();
}

Цепные сравнения

CoffeeScript заимствует цепные сравнения из Python — что упрощает проверку, попадает ли значение в определённый диапазон.

cholesterol = 127

healthy = 200 > cholesterol > 60
var cholesterol, healthy;

cholesterol = 127;

healthy = (200 > cholesterol && cholesterol > 60);

Интерполяция строк, блочные строки и блочные комментарии

В CoffeeScript включена интерполяция строк в стиле Ruby. Строки в двойных кавычках позволяют интерполировать значения, используя #{ … }, а строки в одинарных кавычках являются буквальными. Вы можете даже использовать интерполяцию в ключах объектов.

author = "Wittgenstein"
quote  = "A picture is a fact. -- #{ author }"

sentence = "#{ 22 / 7 } is a decent approximation of π"
var author, quote, sentence;

author = "Wittgenstein";

quote = "A picture is a fact. -- " + author;

sentence = (22 / 7) + " is a decent approximation of π";

В CoffeeScript разрешены многострочные строки. Строки соединяются одним пробелом, если не заканчиваются обратной косой чертой. Отступы игнорируются.

mobyDick = "Call me Ishmael. Some years ago --
  never mind how long precisely -- having little
  or no money in my purse, and nothing particular
  to interest me on shore, I thought I would sail
  about a little and see the watery part of the
  world..."
var mobyDick;

mobyDick = "Call me Ishmael. Some years ago -- never mind how long precisely -- having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world...";

Блочные строки могут использоваться для хранения форматированного или чувствительного к отступам текста (или, если вы просто не хотите экранировать кавычки и апострофы). Уровень отступа, который начинает блок, сохраняется на протяжении всего процесса, поэтому вы можете сохранить его, выровненным с телом вашего кода.

html = """
       <strong>
         cup of coffeescript
       </strong>
       """
var html;

html = "<strong>\n  cup of coffeescript\n</strong>";

Блочные строки в двойных кавычках, как и другие строки в двойных кавычках, позволяют интерполяцию.

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

###
SkinnyMochaHalfCaffScript Compiler v1.0
Released under the MIT License
###
/*
SkinnyMochaHalfCaffScript Compiler v1.0
Released under the MIT License
 */

Размеченные шаблоны строк

CoffeeScript поддерживает размеченные шаблоны строк ES2015, которые позволяют настраивать интерполяцию строк. Если вы сразу же добавите имя функции к строке (без пробела между ними), CoffeeScript выведет эту комбинацию «функция плюс строка» как размеченный шаблон строки ES2015, который будет соответствовать: функция вызывается с параметрами, которые представляют собой входной текст и части выражений, составляющие интерполированную строку. Затем функция может собрать эти части в выходную строку, обеспечивая пользовательскую интерполяцию строк.

Обратите внимание, что компилятор CoffeeScript выводит синтаксис ES2015 для этой функции, поэтому ваша целевая среда выполнения JavaScript должна поддерживать этот синтаксис, чтобы ваш код работал; или вы можете использовать инструменты, такие как Babel или Traceur Compiler, чтобы преобразовать этот синтаксис ES2015 в совместимый JavaScript.

upperCaseExpr = (textParts, expressions...) ->
  textParts.reduce (text, textPart, i) ->
    text + expressions[i - 1].toUpperCase() + textPart

greet = (name, adjective) ->
  upperCaseExpr"""
               Hi #{name}. You look #{adjective}!
               """
var greet, upperCaseExpr,
  slice = [].slice;

upperCaseExpr = function() {
  var expressions, textParts;
  textParts = arguments[0], expressions = 2 <= arguments.length ? slice.call(arguments, 1) : [];
  return textParts.reduce(function(text, textPart, i) {
    return text + expressions[i - 1].toUpperCase() + textPart;
  });
};

greet = function(name, adjective) {
  return upperCaseExpr`Hi ${name}. You look ${adjective}!`;
};

Блоковые регулярные выражения

Аналогично блочным строкам и комментариям, CoffeeScript поддерживает блочные регулярные выражения — расширенные регулярные выражения, которые игнорируют внутренние пробелы и могут содержать комментарии и интерполяцию. Моделированные по модификатору /x в Perl, блочные регулярные выражения CoffeeScript ограничиваются /// и значительно повышают читаемость сложных регулярных выражений. Цитата из исходного кода CoffeeScript:

OPERATOR = /// ^ (
  ?: [-=]>             # function
   | [-+*/%<>&|^!?=]=  # compound assign / compare
   | >>>=?             # zero-fill right shift
   | ([-+:])\1         # doubles
   | ([&|<>])\2=?      # logic / shift
   | \?\.              # soak access
   | \.{2,3}           # range or splat
) ///
var OPERATOR;

OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;

Модули

Модули ES2015 поддерживаются в CoffeeScript с очень похожим синтаксисом import и export:

import 'local-file.coffee'
import 'coffeescript'

import _ from 'underscore'
import * as underscore from 'underscore'

import { now } from 'underscore'
import { now as currentTimestamp } from 'underscore'
import { first, last } from 'underscore'
import utilityBelt, { each } from 'underscore'

export default Math
export square = (x) -> x * x
export class Mathematics
  least: (x, y) -> if x < y then x else y

export { sqrt }
export { sqrt as squareRoot }
export { Mathematics as default, sqrt as squareRoot }

export * from 'underscore'
export { max, min } from 'underscore'
import 'local-file.coffee';

import 'coffeescript';

import _ from 'underscore';

import * as underscore from 'underscore';

import {
  now
} from 'underscore';

import {
  now as currentTimestamp
} from 'underscore';

import {
  first,
  last
} from 'underscore';

import utilityBelt, {
  each
} from 'underscore';

export default Math;

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

export var Mathematics = (function() {
  function Mathematics() {}

  Mathematics.prototype.least = function(x, y) {
    if (x < y) {
      return x;
    } else {
      return y;
    }
  };

  return Mathematics;

})();

export {
  sqrt
};

export {
  sqrt as squareRoot
};

export {
  Mathematics as default,
  sqrt as squareRoot
};

export * from 'underscore';

export {
  max,
  min
} from 'underscore';

Обратите внимание, что компилятор CoffeeScript не разрешает модули; запись оператора import или export в CoffeeScript приведет к оператору import или export в результирующем выводе. Вам необходимо подключить другой транспилятор, такой как Traceur Compiler, Babel или Rollup, для преобразования этого синтаксиса ES2015 в код, который будет работать в вашей целевой среде выполнения.

Также обратите внимание, что любой файл с оператором import или export будет выведен без обёртки безопасности функции верхнего уровня; другими словами, импорт или экспорт модулей автоматически запустит режим без обёртки для этого файла. Это связано с тем, что согласно спецификации ES2015, операторы import или export должны находиться в самом верхнем уровне области видимости.

Cake и Cakefiles

CoffeeScript включает в себя (очень) простую систему сборки, аналогичную Make и Rake. Естественно, она называется Cake и используется для задач, которые собирают и тестируют сам язык CoffeeScript. Задачи определяются в файле с именем Cakefile, и могут быть вызваны путём выполнения cake [task] из каталога. Чтобы вывести список всех задач и опций, просто введите cake.

Определения задач написаны на CoffeeScript, поэтому вы можете вставить произвольный код в свой Cakefile. Определите задачу с именем, подробным описанием и функцией, которая будет вызвана при выполнении задачи. Если ваша задача принимает параметр командной строки, вы можете определить этот параметр с помощью коротких и длинных флагов, и он будет доступен в объекте options. Вот задача, которая использует API Node.js для перестроения парсера CoffeeScript:

fs = require 'fs'

option '-o', '--output [DIR]', 'directory for compiled code'

task 'build:parser', 'rebuild the Jison parser', (options) ->
  require 'jison'
  code = require('./lib/grammar').parser.generate()
  dir  = options.output or 'lib'
  fs.writeFile "#{dir}/parser.js", code
var fs;

fs = require('fs');

option('-o', '--output [DIR]', 'directory for compiled code');

task('build:parser', 'rebuild the Jison parser', function(options) {
  var code, dir;
  require('jison');
  code = require('./lib/grammar').parser.generate();
  dir = options.output || 'lib';
  return fs.writeFile(dir + "/parser.js", code);
});

Если вам нужно вызвать одну задачу перед другой — например, выполнить build перед test, вы можете использовать функцию invoke: invoke 'build'. Задачи Cake — это минимальный способ сделать ваши функции CoffeeScript доступными в командной строке, поэтому не ожидайте никаких изысков встроенных в них. Если вам нужны зависимости или асинхронные обратные вызовы, лучше поместить их в сам код, а не в задачу Cake.

Карты исходных кодов

CoffeeScript 1.6.1 и выше включают поддержку генерации карт исходных кодов — способ указать вашему движку JavaScript, какая часть вашей программы CoffeeScript соответствует оцениваемому коду. Браузеры, которые поддерживают это, могут автоматически использовать карты исходных кодов, чтобы отобразить ваш исходный код в отладчике. Чтобы сгенерировать карты исходных кодов вместе с файлами JavaScript, передайте флаг --map или -m компилятору.

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

Теги скрипта “text/coffeescript”

Хотя это не рекомендуется для серьезного использования, CoffeeScript можно включить непосредственно в браузере с помощью тегов <script type="text/coffeescript">. Исходный код включает сжатую и минифицированную версию компилятора (Скачать текущую версию здесь, 51к после сжатия) как docs/v1/browser-compiler/coffee-script.js. Включите этот файл на странице с тегами CoffeeScript в строке, и он будет компилировать и выводить их в порядке следования.

На самом деле, небольшой скрипт-«склейка», который выполняет «Попробовать CoffeeScript» выше, а также jQuery для меню, реализованы именно таким способом. Посмотрите исходный код и посмотрите внизу страницы, чтобы увидеть пример. Включение скрипта также дает вам доступ к CoffeeScript.compile(), чтобы вы могли открыть Firebug и попробовать скомпилировать некоторые строки.

Применимы стандартные замечания по CoffeeScript — ваши встроенные скрипты будут выполняться в оболочке closure, поэтому, если вы хотите экспонировать глобальные переменные или функции, прикрепите их к объекту window.

© 2009–2018 Jeremy Ashkenas
Licensed under the MIT License.
https://coffeescript.org/v1/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API