Перевод выполнен в компании Аринт.

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

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

Последняя версия: 1.6.3

sudo npm install -g coffee-script

Обзор

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

# Присвоение:
number   = 42
opposite = true

# Условия:
number = -42 if opposite

# Функции:
square = (x) -> x * x

# Массивы:
list = [1, 2, 3, 4, 5]

# Объекты:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Многоточие:
race = (winner, runners...) ->
  print winner, runners

# Существование:
alert "I knew it!" if elvis?

# Итерации по массивам:
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;
})();
run: cubes

Установка

Компилятор CoffeeScript сам написан на CoffeeScript, используя генератор синтаксических анализаторов Jison. Версия coffee для командной строки доступна, как утилита Node.js. Ядро компилятора, однако не зависит от Node и может быть запущено в любом JavaScript-окружении, в том числе в браузере (смотрите выше кнопку "Попробовать CoffeeScript").

Перед установкой сначала убедитесь, что у вас есть работоспособная копия последней стабильной версии Node.js и npm (Node Package Manager). Вы можете установить CoffeeScript через npm:

npm install -g coffee-script

(Опустите -g, если вы не хотите устанавливать глобально)

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

npm install -g http://github.com/jashkenas/coffee-script/tarball/master

Или, если вы хотите установить в /usr/local, и не хотите использовать npm для управления, откройте директорию coffee-script и запустите:

sudo bin/cake install

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

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

-c, --compile Комилирует скрипт .coffee в .js файл JavaScript с тем же именем.
-m, --map Генерирует карту исходников рядом с компилированными файлами JavaScript, а также добавляет директивы sourceMappingURL к JavaScript.
-i, --interactive Запускает интерактивную сессию CoffeeScript, чтобы пробовать короткие фрагменты. Идентично вызову coffee без аргументов.
-o, --output [DIR] Записывает весь компилированный вывод JavaScript файлов в указанную директорию. Используйте совместно с --compile или --watch.
-j, --join [FILE] Перед компиляцией объединяет все скрипты вместе, в том порядке, в котором они были переданы, и записывает их в указанный файл. Полезно для сборки больших проектов.
-w, --watch Следит за изменениями файлов, автоматически перезапуская указанную команду при обновлении файлов.
-p, --print Вместо того, чтобы записывать JavaScript в файл, выводит напрямую в stdout.
-s, --stdio Принимает CoffeeScript в STDIN и возвращает JavaScript в STDOUT. Полезно для использования с процессами, написанными на других языках. Пример:
cat src/cake.coffee | coffee -sc
-l, --literate Парсит код, как литературный CoffeeScript. Вам нужно только указать это при передаче кода в stdio, или использовать имя файла без расширения.
-e, --eval Компилирует и выводит небольшой кусок CoffeeScript прямо в командную строку. Например:
coffee -e "console.log num for num in [10..1]"
-b, --bare Компилирует JavaScript без высокоуровневой функции-обертки.
-t, --tokens В отличие от разбора CoffeeScript, только проверяет орфографию и выводит поток токенов: [IDENTIFIER square] [ASSIGN =] [PARAM_START (] ...
-n, --nodes В отличие от компиляции CoffeeScript, только провереят орфографию, парсит и выводит дерево парсинга:
Expressions
  Assign
    Value "square"
    Code "x"
      Op *
        Value "x"
        Value "x"
--nodejs node имеет несколько полезных опций, которые вы можете установить, такие как --debug, --debug-brk, --max-stack-size и --expose-gc. Используйте этот флаг, чтобы направлять опции напрямую Node.js. Чтобы передать несколько флагов, используйте несколько элементов --nodejs.

Примеры:

Литературный CoffeeScript

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

Ради интереса, можете посмотреть это: как документ, в строчном режиме, и правильную подсветку в текстовом редакторе.

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

Справка по языку

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

Большинство примеров можно запустить, нажав кнопку run справа, а также можно загрузить в консоль "Попробуйте CoffeeScript", нажав load слева.

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

Вы не обязаны использовать круглые скобки для вызова функции при передаче аргументов. Обертывание происходит автоматически, до конца строки или блока выражений: console.log sys.inspect objectconsole.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;
};
load
run: cube(5)

Функции также могут иметь значения по умолчанию для своих аргументов. Значение по умолчанию заменяется передачей ненулевого аргумента.

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 + "...";
};
load
run: fill("cup")

Объекты и массивы Литералы 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
  }
};
load
run: song.join(" ... ")

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

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

log object.class


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

log(object["class"]);
load

Лексический контекст и безопасность переменных Компилятор 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();
load
run: inner

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

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

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

Если вы захотите создать глобальные переменные для использования другими скриптами, сделайте их свойством window, или экспорт объекта CommonJS. Оператор для проверки существования переменной, описанный ниже, дает вам надежный способ выяснить, куда добавлять их, если вы для ориентирования по коду используете 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;
load

Многоточие... Объект аргумента JavaScript является удобным способом работы с функциями, которые принимают переменное количество аргументов. 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);
load
run

Циклы и генераторы Большая часть циклов, которые вы будете использовать в CoffeeScript, будут генераторами над массивами, объектами и диапазонами. Генераторы заменяют (и компилируют в) циклы 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, _i, _j, _k, _len, _len1, _len2, _ref;

_ref = ['toast', 'cheese', 'wine'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  food = _ref[_i];
  eat(food);
}

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

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

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

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

Генераторы должны быть в состоянии обрабатывать большую часть случаев, где вы могли бы использовать циклы 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;
})();
load
run: countdown

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

Для определения шага цикла можно использовать by, например:
evens = (x for x in [0..10] by 2)

Генераторы также могут быть использованы для перебора свойств и значений объекта. Использование оператора 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;
})();
load
run: ages.join(", ")

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

Только низкоуровневые циклы в 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;
})();
load
run: lyrics.join("\n")

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

При использовании циклов JavaScript в качестве генерирующих функций, обычно вставляется закрывающая обертка для того, чтобы защитить переменные цикла, и все сгенерированные функции не только возаращают финальные значения. CoffeeSсript предоставляет ключевое слово 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);
}
load

Нарезка массивов и соединение с диапазонами Диапазоны также могут быть использованы для извлечения отрезков из массовов. Диапазон, определенный двумя точками 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...6]

end     = numbers[6..]

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, 6);

end = numbers.slice(6);

copy = numbers.slice(0);
load
run: middle

Такой же синтаксис можно использовать при замене частей массива присвоением, сращивая их.

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;
load
run: numbers

Обратите внимание, строки 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";
load
run: eldest

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

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

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


var one, six, three, two;

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

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

# Первые десять глобальных свойств.

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);
load
run: globals

Как и глупые вещи, вроде передачи объявления try/catch прямо в вызов функции:

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

var error;

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

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

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

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

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

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

В соответствии с YAML, on и yes это тоже, что и булево true, а off и no соответствуют булевому false.

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

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

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

Теперь все вместе:

CoffeeScriptJavaScript
is===
isnt!==
not!
and&&
or||
true, yes, ontrue
false, no, offfalse
@, thisthis
ofin
inno JS equivalent
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));
load

Оператор проверки существования Проверять существование переменных в JavaScript сложновато. if (variable) ... близко, но не корректно для нуля, пустой строки, и false. Оператор проверки существования 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";
load
run: footprints

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

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

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

"Впитывание" нулей соответствует Ruby andand gem и оператору безопасной навигации в Groovy.

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

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

Функция конструктора имеет название, для лучшей поддержки трассировки стека. В первом классе в примере ниже this.constructor.name это "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, _ref, _ref1,
  __hasProp = {}.hasOwnProperty,
  __extends = 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; };

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

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

  return Animal;

})();

Snake = (function(_super) {
  __extends(Snake, _super);

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

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

  return Snake;

})(Animal);

Horse = (function(_super) {
  __extends(Horse, _super);

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

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

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

String::dasherize = ->
  this.replace /_/g, "-"

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

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

Реструктурирующее присваивание Чтобы сделать получение значений из комплексных массивов и объектов более удобным, CoffeeScript выполняет синтаксис ECMAScript Harmony реструктурирующего присваивания. Когда вы присваиваете массив или литерал объекта значению, CoffeeScript разделяет и проверяет соответвие обеих сторон, присваивая значения справа значениям слева. В простейшем случае это может быть использовано для параллельного присвоения:

theBait   = 1000
theSwitch = 0

[theBait, theSwitch] = [theSwitch, theBait]




 
var theBait, theSwitch, _ref;

theBait = 1000;

theSwitch = 0;

_ref = [theSwitch, theBait], theBait = _ref[0], theSwitch = _ref[1];
load
run: theBait

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

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

[city, temp, forecast] = weatherReport "Berkeley, CA"




var city, forecast, temp, weatherReport, _ref;

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

_ref = weatherReport("Berkeley, CA"), city = _ref[0], temp = _ref[1], forecast = _ref[2];
load
run: forecast

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

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

{poet: {name, address: [street, city]}} = futurists



var city, futurists, name, street, _ref, _ref1;

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

_ref = futurists.poet, name = _ref.name, (_ref1 = _ref.address, street = _ref1[0], city = _ref1[1]);
load
run: name + " — " + street

Реструктурирующее присваивание может быть объединено с многоточием.

tag = "<impossible>"

[open, contents..., close] = tag.split("")






var close, contents, open, tag, _i, _ref,
  __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++];
load
run: contents.join("")

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

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

var Person;

Person = (function() {
  function Person(options) {
    this.name = options.name, this.age = options.age, this.height = options.height;
  }

  return Person;

})();
load
run: contents.join("")

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

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

Примечание переводчика. При назначении через CoffeeScript обработчиков событий jQuery $(this) теряется. Вместо него можно использовать $(event.target).
Account = (customer, cart) ->
  @customer = customer
  @cart = cart

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

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

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

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

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

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



var hi;

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

Switch/When/Else Условие Switch в JavaScript несколько неудобное. Вы должны помнить о break в конце каждого условия case, чтобы предотарвтить непроизвольное выполнение условия по умолчанию. 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);
}
load

Условие 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';
  }
})();
load

Try/Catch/Finally Условия try/catch такие же, как и в JavaScript, за исключением того, что они работают, как выражения.

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

var error;

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

Сцепление сравнений CoffeeScript заимствует сцепленные сравнения из Python - позволяя легко проверять, что значение находится в определенном диапазоне.

cholesterol = 127

healthy = 200 > cholesterol > 60


var cholesterol, healthy;

cholesterol = 127;

healthy = (200 > cholesterol && cholesterol > 60);
load
run: healthy

Интерполяция строк, блоки строк и блоки комментариев В 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 π";
load
run: sentence

Многострочные блоки доступны в 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...";
load
run: mobyDick

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

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

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

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

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

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


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


load

Блоки регулярных выражений Также, как и блоки строк и комментариев, CoffeeScript поддерживает блоки регексов - расширенных регулярных выражений. По модели Perl-овского модификатора /x, блоки регулярных выражений 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})/;
load

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

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

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

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

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

Теги "text/coffeescript"

Пока это не рекомендовано для серьезного использования. CoffeeScript может быть включен прямо в браузер, используя теги <script type="text/coffeescript">. Источник содержит сжатую и минифицированную версию компилятора (Загрузите текущую версию тут, 39k в сжатом виде) как extras/coffee-script.js. Подключите этот файл на страницу с тегами CoffeeScript, и он скомилирует и выполнит их.

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

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

Книги

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

Screencasts

Examples

The best list of open-source CoffeeScript examples can be found on GitHub. But just to throw out few more:

Resources

Web Chat (IRC)

Quick help and advice can usually be found in the CoffeeScript IRC room. Join #coffeescript on irc.freenode.net, or click the button below to open a webchat session on this page.

Change Log

1.6.3 June 2, 2013

1.6.2 March 18, 2013

1.6.1 March 5, 2013

1.5.0 Feb 25, 2013

1.4.0 Oct 23, 2012

1.3.3 May 15, 2012

1.3.1 April 10, 2012

1.2.0 Dec. 18, 2011

1.1.3 Nov. 8, 2011

1.1.2 August 4, 2011 Fixes for block comment formatting, ?= compilation, implicit calls against control structures, implicit invocation of a try/catch block, variadic arguments leaking from local scope, line numbers in syntax errors following heregexes, property access on parenthesized number literals, bound class methods and super with reserved names, a REPL overhaul, consecutive compiled semicolons, block comments in implicitly called objects, and a Chrome bug.

1.1.1 May 10, 2011 Bugfix release for classes with external constructor functions, see issue #1182.

1.1.0 May 1, 2011 When running via the coffee executable, process.argv and friends now report coffee instead of node. Better compatibility with Node.js 0.4.x module lookup changes. The output in the REPL is now colorized, like Node's is. Giving your concatenated CoffeeScripts a name when using --join is now mandatory. Fix for lexing compound division /= as a regex accidentally. All text/coffeescript tags should now execute in the order they're included. Fixed an issue with extended subclasses using external constructor functions. Fixed an edge-case infinite loop in addImplicitParentheses. Fixed exponential slowdown with long chains of function calls. Globals no longer leak into the CoffeeScript REPL. Splatted parameters are declared local to the function.

1.0.1 Jan 31, 2011 Fixed a lexer bug with Unicode identifiers. Updated REPL for compatibility with Node.js 0.3.7. Fixed requiring relative paths in the REPL. Trailing return and return undefined are now optimized away. Stopped requiring the core Node.js "util" module for back-compatibility with Node.js 0.2.5. Fixed a case where a conditional return would cause fallthrough in a switch statement. Optimized empty objects in destructuring assignment.

1.0.0 Dec 24, 2010 CoffeeScript loops no longer try to preserve block scope when functions are being generated within the loop body. Instead, you can use the do keyword to create a convenient closure wrapper. Added a --nodejs flag for passing through options directly to the node executable. Better behavior around the use of pure statements within expressions. Fixed inclusive slicing through -1, for all browsers, and splicing with arbitrary expressions as endpoints.

0.9.6 Dec 6, 2010 The REPL now properly formats stacktraces, and stays alive through asynchronous exceptions. Using --watch now prints timestamps as files are compiled. Fixed some accidentally-leaking variables within plucked closure-loops. Constructors now maintain their declaration location within a class body. Dynamic object keys were removed. Nested classes are now supported. Fixes execution context for naked splatted functions. Bugfix for inversion of chained comparisons. Chained class instantiation now works properly with splats.

0.9.5 Nov 21, 2010 0.9.5 should be considered the first release candidate for CoffeeScript 1.0. There have been a large number of internal changes since the previous release, many contributed from satyr's Coco dialect of CoffeeScript. Heregexes (extended regexes) were added. Functions can now have default arguments. Class bodies are now executable code. Improved syntax errors for invalid CoffeeScript. undefined now works like null, and cannot be assigned a new value. There was a precedence change with respect to single-line comprehensions: result = i for i in list
used to parse as result = (i for i in list) by default ... it now parses as
(result = i) for i in list.

0.9.4 Sep 21, 2010 CoffeeScript now uses appropriately-named temporary variables, and recycles their references after use. Added require.extensions support for Node.js 0.3. Loading CoffeeScript in the browser now adds just a single CoffeeScript object to global scope. Fixes for implicit object and block comment edge cases.

0.9.3 Sep 16, 2010 CoffeeScript switch statements now compile into JS switch statements — they previously compiled into if/else chains for JavaScript 1.3 compatibility. Soaking a function invocation is now supported. Users of the RubyMine editor should now be able to use --watch mode.

0.9.2 Aug 23, 2010 Specifying the start and end of a range literal is now optional, eg. array[3..]. You can now say a not instanceof b. Fixed important bugs with nested significant and non-significant indentation (Issue #637). Added a --require flag that allows you to hook into the coffee command. Added a custom jsl.conf file for our preferred JavaScriptLint setup. Sped up Jison grammar compilation time by flattening rules for operations. Block comments can now be used with JavaScript-minifier-friendly syntax. Added JavaScript's compound assignment bitwise operators. Bugfixes to implicit object literals with leading number and string keys, as the subject of implicit calls, and as part of compound assignment.

0.9.1 Aug 11, 2010 Bugfix release for 0.9.1. Greatly improves the handling of mixed implicit objects, implicit function calls, and implicit indentation. String and regex interpolation is now strictly #{ ... } (Ruby style). The compiler now takes a --require flag, which specifies scripts to run before compilation.

0.9.0 Aug 4, 2010 The CoffeeScript 0.9 series is considered to be a release candidate for 1.0; let's give her a shakedown cruise. 0.9.0 introduces a massive backwards-incompatible change: Assignment now uses =, and object literals use :, as in JavaScript. This allows us to have implicit object literals, and YAML-style object definitions. Half assignments are removed, in favor of +=, or=, and friends. Interpolation now uses a hash mark # instead of the dollar sign $ — because dollar signs may be part of a valid JS identifier. Downwards range comprehensions are now safe again, and are optimized to straight for loops when created with integer endpoints. A fast, unguarded form of object comprehension was added: for all key, value of object. Mentioning the super keyword with no arguments now forwards all arguments passed to the function, as in Ruby. If you extend class B from parent class A, if A has an extended method defined, it will be called, passing in B — this enables static inheritance, among other things. Cleaner output for functions bound with the fat arrow. @variables can now be used in parameter lists, with the parameter being automatically set as a property on the object — useful in constructors and setter functions. Constructor functions can now take splats.

0.7.2 Jul 12, 2010 Quick bugfix (right after 0.7.1) for a problem that prevented coffee command-line options from being parsed in some circumstances.

0.7.1 Jul 11, 2010 Block-style comments are now passed through and printed as JavaScript block comments -- making them useful for licenses and copyright headers. Better support for running coffee scripts standalone via hashbangs. Improved syntax errors for tokens that are not in the grammar.

0.7.0 Jun 28, 2010 Official CoffeeScript variable style is now camelCase, as in JavaScript. Reserved words are now allowed as object keys, and will be quoted for you. Range comprehensions now generate cleaner code, but you have to specify by -1 if you'd like to iterate downward. Reporting of syntax errors is greatly improved from the previous release. Running coffee with no arguments now launches the REPL, with Readline support. The <- bind operator has been removed from CoffeeScript. The loop keyword was added, which is equivalent to a while true loop. Comprehensions that contain closures will now close over their variables, like the semantics of a forEach. You can now use bound function in class definitions (bound to the instance). For consistency, a in b is now an array presence check, and a of b is an object-key check. Comments are no longer passed through to the generated JavaScript.

0.6.2 May 15, 2010 The coffee command will now preserve directory structure when compiling a directory full of scripts. Fixed two omissions that were preventing the CoffeeScript compiler from running live within Internet Explorer. There's now a syntax for block comments, similar in spirit to CoffeeScript's heredocs. ECMA Harmony DRY-style pattern matching is now supported, where the name of the property is the same as the name of the value: {name, length}: func. Pattern matching is now allowed within comprehension variables. unless is now allowed in block form. until loops were added, as the inverse of while loops. switch statements are now allowed without switch object clauses. Compatible with Node.js v0.1.95.

0.6.1 Apr 12, 2010 Upgraded CoffeeScript for compatibility with the new Node.js v0.1.90 series.

0.6.0 Apr 3, 2010 Trailing commas are now allowed, a-la Python. Static properties may be assigned directly within class definitions, using @property notation.

0.5.6 Mar 23, 2010 Interpolation can now be used within regular expressions and heredocs, as well as strings. Added the <- bind operator. Allowing assignment to half-expressions instead of special ||=-style operators. The arguments object is no longer automatically converted into an array. After requiring coffee-script, Node.js can now directly load .coffee files, thanks to registerExtension. Multiple splats can now be used in function calls, arrays, and pattern matching.

0.5.5 Mar 8, 2010 String interpolation, contributed by Stan Angeloff. Since --run has been the default since 0.5.3, updating --stdio and --eval to run by default, pass --compile as well if you'd like to print the result.

0.5.4 Mar 3, 2010 Bugfix that corrects the Node.js global constants __filename and __dirname. Tweaks for more flexible parsing of nested function literals and improperly-indented comments. Updates for the latest Node.js API.

0.5.3 Feb 27, 2010 CoffeeScript now has a syntax for defining classes. Many of the core components (Nodes, Lexer, Rewriter, Scope, Optparse) are using them. Cakefiles can use optparse.coffee to define options for tasks. --run is now the default flag for the coffee command, use --compile to save JavaScripts. Bugfix for an ambiguity between RegExp literals and chained divisions.

0.5.2 Feb 25, 2010 Added a compressed version of the compiler for inclusion in web pages as
extras/coffee-script.js. It'll automatically run any script tags with type text/coffeescript for you. Added a --stdio option to the coffee command, for piped-in compiles.

0.5.1 Feb 24, 2010 Improvements to null soaking with the existential operator, including soaks on indexed properties. Added conditions to while loops, so you can use them as filters with when, in the same manner as comprehensions.

0.5.0 Feb 21, 2010 CoffeeScript 0.5.0 is a major release, While there are no language changes, the Ruby compiler has been removed in favor of a self-hosting compiler written in pure CoffeeScript.

0.3.2 Feb 8, 2010 @property is now a shorthand for this.property.
Switched the default JavaScript engine from Narwhal to Node.js. Pass the --narwhal flag if you'd like to continue using it.

0.3.0 Jan 26, 2010 CoffeeScript 0.3 includes major syntax changes:
The function symbol was changed to ->, and the bound function symbol is now =>.
Parameter lists in function definitions must now be wrapped in parentheses.
Added property soaking, with the ?. operator.
Made parentheses optional, when invoking functions with arguments.
Removed the obsolete block literal syntax.

0.2.6 Jan 17, 2010 Added Python-style chained comparisons, the conditional existence operator ?=, and some examples from Beautiful Code. Bugfixes relating to statement-to-expression conversion, arguments-to-array conversion, and the TextMate syntax highlighter.

0.2.5 Jan 13, 2010 The conditions in switch statements can now take multiple values at once — If any of them are true, the case will run. Added the long arrow ==>, which defines and immediately binds a function to this. While loops can now be used as expressions, in the same way that comprehensions can. Splats can be used within pattern matches to soak up the rest of an array.

0.2.4 Jan 12, 2010 Added ECMAScript Harmony style destructuring assignment, for dealing with extracting values from nested arrays and objects. Added indentation-sensitive heredocs for nicely formatted strings or chunks of code.

0.2.3 Jan 11, 2010 Axed the unsatisfactory ino keyword, replacing it with of for object comprehensions. They now look like: for prop, value of object.

0.2.2 Jan 10, 2010 When performing a comprehension over an object, use ino, instead of in, which helps us generate smaller, more efficient code at compile time.
Added :: as a shorthand for saying .prototype.
The "splat" symbol has been changed from a prefix asterisk *, to a postfix ellipsis ...
Added JavaScript's in operator, empty return statements, and empty while loops.
Constructor functions that start with capital letters now include a safety check to make sure that the new instance of the object is returned.
The extends keyword now functions identically to goog.inherits in Google's Closure Library.

0.2.1 Jan 5, 2010 Arguments objects are now converted into real arrays when referenced.

0.2.0 Jan 5, 2010 Major release. Significant whitespace. Better statement-to-expression conversion. Splats. Splice literals. Object comprehensions. Blocks. The existential operator. Many thanks to all the folks who posted issues, with special thanks to Liam O'Connor-Davis for whitespace and expression help.

0.1.6 Dec 27, 2009 Bugfix for running coffee --interactive and --run from outside of the CoffeeScript directory. Bugfix for nested function/if-statements.

0.1.5 Dec 26, 2009 Array slice literals and array comprehensions can now both take Ruby-style ranges to specify the start and end. JavaScript variable declaration is now pushed up to the top of the scope, making all assignment statements into expressions. You can use \ to escape newlines. The coffee-script command is now called coffee.

0.1.4 Dec 25, 2009 The official CoffeeScript extension is now .coffee instead of .cs, which properly belongs to C#. Due to popular demand, you can now also use = to assign. Unlike JavaScript, = can also be used within object literals, interchangeably with :. Made a grammatical fix for chained function calls like func(1)(2)(3)(4). Inheritance and super no longer use __proto__, so they should be IE-compatible now.

0.1.3 Dec 25, 2009 The coffee command now includes --interactive, which launches an interactive CoffeeScript session, and --run, which directly compiles and executes a script. Both options depend on a working installation of Narwhal. The aint keyword has been replaced by isnt, which goes together a little smoother with is. Quoted strings are now allowed as identifiers within object literals: eg. {"5+5": 10}. All assignment operators now use a colon: +:, -:, *:, etc.

0.1.2 Dec 24, 2009 Fixed a bug with calling super() through more than one level of inheritance, with the re-addition of the extends keyword. Added experimental Narwhal support (as a Tusk package), contributed by Tom Robinson, including bin/cs as a CoffeeScript REPL and interpreter. New --no-wrap option to suppress the safety function wrapper.

0.1.1 Dec 24, 2009 Added instanceof and typeof as operators.

0.1.0 Dec 24, 2009 Initial CoffeeScript release.

Яндекс.Метрика