LEARN X · ЗА 13 МИН

CoffeeScript

CoffeeScript за 13 минут: весь язык на одной странице через комментированный код — синтаксис, функции, классы, comprehensions и компиляция в JS.

CoffeeScript — это «синтаксический сахар» поверх JavaScript: тот же язык, но с чистым синтаксисом без лишних скобок и точек с запятой. Любой код компилируется в обычный читаемый JS. Весь язык — ниже, в комментариях к коду.

Философия и вывод

Значимые отступы вместо фигурных скобок, минимум знаков препинания.

# Это однострочный комментарий
###
А это блочный комментарий:
всё между тройными решётками — комментарий
###

# Вывод в консоль (это обычный JS console.log)
console.log "Привет, CoffeeScript!"   # скобки вызова можно опускать
console.log("Со скобками тоже работает")

# Блоки кода задаются ОТСТУПАМИ, а не { }
# Нет точек с запятой в конце строк
# Нет var — об этом ниже

Переменные

Никакого var: CoffeeScript сам объявляет переменные в безопасной области видимости.

# Просто присваивание — без var/let/const
name = "Аня"
age  = 25
pi   = 3.14

# CoffeeScript оборачивает весь файл в функцию,
# поэтому переменные не утекают в глобальную область.
# Объявление создаётся автоматически в той области,
# где переменная впервые присвоена.

counter = 0
counter += 1        # 1

# Перезапись существующей переменной не создаёт новую
name = "Борис"      # та же переменная name

Строки

Интерполяция через #{ }, многострочные и блочные строки.

user = "Маша"

# Интерполяция работает в двойных кавычках
greeting = "Привет, #{user}!"          # "Привет, Маша!"
math     = "2 + 2 = #{2 + 2}"          # "2 + 2 = 4"

# Одинарные кавычки — без интерполяции (буквально)
raw = 'Тут #{user} не подставится'

# Многострочная строка
letter = "Дорогой друг,
         я пишу тебе письмо"

# Блочная строка (сохраняет переносы, тройные кавычки)
html = """
       <div>
         #{user}
       </div>
       """

Функции

Стрелка -> определяет функцию, => привязывает this.

# Функция: (аргументы) -> тело
square = (x) -> x * x        # последнее выражение возвращается
console.log square 5         # 25  (скобки вызова опциональны)

# Многострочная функция — телом служит блок с отступом
greet = (name) ->
  msg = "Привет, #{name}"
  msg                        # неявный return

# Аргументы по умолчанию
pow = (base, exp = 2) -> Math.pow base, exp
console.log pow 3            # 9

# Splat ... — переменное число аргументов
sum = (nums...) ->
  total = 0
  total += n for n in nums
  total
console.log sum 1, 2, 3, 4   # 10

# Жирная стрелка => сохраняет контекст this (@)
obj =
  items: [1, 2, 3]
  show: ->
    @items.forEach (x) =>   # => чтобы @ остался obj
      console.log x

Условия

if/else, unless, постфиксная форма, switch/when.

age = 18

if age >= 18
  console.log "Совершеннолетний"
else
  console.log "Несовершеннолетний"

# unless — это "если НЕ"
unless age >= 18
  console.log "Ещё рано"

# Постфиксная (однострочная) форма
console.log "Можно!" if age >= 18
console.log "Стоп"   unless age >= 18

# if — это выражение, возвращает значение
status = if age >= 18 then "взрослый" else "ребёнок"

# switch / when (без break, можно несколько значений)
day = "сб"
switch day
  when "сб", "вс" then console.log "Выходной"
  when "пт"       then console.log "Почти выходной"
  else                console.log "Будний день"

Сравнения и логика

Читаемые операторы is/isnt/and/or/not и проверка существования ?.

a = 5
b = 5

# is  → ===   isnt → !==   (строгое сравнение)
console.log a is b          # true
console.log a isnt 3        # true

# and → &&   or → ||   not → !
console.log (a > 0 and b > 0)   # true
console.log (a > 9 or b is 5)   # true
console.log (not false)         # true

# Оператор существования ?  (не null и не undefined)
name = null
console.log name?              # false

# Значение по умолчанию, если переменной нет
greeting = name ? "Гость"      # "Гость"

# Безопасный доступ ?. — не упадёт на null
user = null
console.log user?.profile?.email   # undefined, без ошибки

# Присвоить, только если пусто
config = null
config ?= { theme: "dark" }

Циклы и comprehensions

Циклы — выражения; comprehensions возвращают массив.

# for ... in — перебор элементов массива
for fruit in ["яблоко", "груша", "слива"]
  console.log fruit

# С индексом
for item, i in ["a", "b", "c"]
  console.log "#{i}: #{item}"

# for ... of — перебор ключей объекта
user = name: "Лена", age: 30
for key, value of user
  console.log "#{key} = #{value}"

# while
i = 0
while i < 3
  console.log i
  i += 1

# List comprehension — собирает результат в массив
squares = (x * x for x in [1..5])      # [1, 4, 9, 16, 25]

# С фильтром through when
evens = (n for n in [1..10] when n % 2 is 0)   # [2,4,6,8,10]

# Постфиксный цикл
console.log n for n in [1, 2, 3]

Массивы и объекты

Диапазоны [1..5], лаконичные литералы и деструктуризация.

# Массив (запятые в конце строк можно опускать)
list = [
  1
  2
  3
]

# Диапазоны
range1 = [1..5]      # [1, 2, 3, 4, 5]  — включительно
range2 = [1...5]     # [1, 2, 3, 4]     — без последнего

# Срезы массива через диапазон
arr = [10, 20, 30, 40, 50]
console.log arr[1..3]     # [20, 30, 40]

# Объект без скобок { } — по отступам
person =
  name: "Игорь"
  age: 40
  city: "Москва"

# Деструктуризация массива
[first, second] = [100, 200]   # first=100, second=200

# Деструктуризация объекта
{name, city} = person          # name="Игорь", city="Москва"

# Splat в деструктуризации
[head, tail...] = [1, 2, 3, 4] # head=1, tail=[2,3,4]

Классы

class, наследование extends, super, @ как this.

class Animal
  # Конструктор. @name — сокращение для this.name
  constructor: (@name, @sound = "...") ->

  # Метод экземпляра
  speak: ->
    console.log "#{@name} говорит: #{@sound}"

# Наследование
class Dog extends Animal
  constructor: (name) ->
    super name, "Гав"      # вызов конструктора родителя

  # Переопределение метода
  speak: ->
    super()                # вызов родительского speak
    console.log "...и виляет хвостом"

rex = new Dog "Рекс"
rex.speak()
# Рекс говорит: Гав
# ...и виляет хвостом

# Статические свойства/методы — через @
class MathUtils
  @double: (x) -> x * 2
console.log MathUtils.double 21   # 42

Всё — выражение

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

# if возвращает значение
label = if 5 > 3 then "больше" else "меньше"

# switch возвращает значение
grade = (score) ->
  switch
    when score >= 90 then "A"
    when score >= 75 then "B"
    else                 "C"
console.log grade 80      # "B"

# try/catch тоже выражение
result = try
  JSON.parse "{ broken"
catch err
  "ошибка разбора"

# Функция неявно возвращает последнее выражение
max = (a, b) ->
  if a > b then a else b   # return не нужен

Компиляция в JavaScript

CoffeeScript не выполняется сам — он переводится в обычный JS.

# Установка компилятора:
#   npm install -g coffeescript
#
# Скомпилировать файл в app.js:
#   coffee --compile app.coffee
#
# Запустить напрямую (через Node):
#   coffee app.coffee
#
# Следить за изменениями и пересобирать:
#   coffee --watch --compile app.coffee

# Пример того, во что превращается код.
# CoffeeScript:
square = (x) -> x * x

# Скомпилированный JavaScript:
#   var square;
#   square = function(x) {
#     return x * x;
#   };

# Вывод: пишешь чисто на CoffeeScript,
# получаешь читаемый и совместимый JavaScript.
Поддержать проект