html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Знакомство с CoffeeScript tutorial

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

CoffeeScript — это маленький язык, который транслируется в JavaScript. Его документация умещается на одной странице — coffeescript.org и отличается компактностью и наглядностью. Я даже сомневался в необходимости данной статьи, когда есть такое классное описание «от производителя», но все же рискнул расставить акценты и прояснить некоторые детали.

Введение


Если копнуть немного истории, то с 2009-го года язык писался на Ruby, с 2010 — он пишется на самом же CoffeeScript.
И в Ruby on Rails, начиная с версии 3.1, он «заменил» JavaScript.

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

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

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

Трансляция кода


Хорошо, как пользоваться этим вашим CoffeeScript?
Удобнее всего, на мой взгляд, работать с ним, как с модулем node.js. Ставится он проще простого:
npm install -g coffee-script

Создаем две папки, для определенности назовем их lib и src.
Создаем файл src/helloWorld.coffee и напишем, что нибудь на CoffeeScript. Например:
console.log('Hello world')

После этого запускаем транслятор:
coffee --compile --output lib/ src/
В итоге в папке lib будет лежать файл helloWorld.js, готовый к выполнению.
Конечно, на каждый чих запускать транслятор не интересно. Запуск команды
coffee -o lib/ -cw src/
заставляет следить за всеми изменениями файлов в папке src и самостоятельно транслировать их в JavaScript-код.

Синтаксис


Функции

Перейдем к самому языку. Напишем простенький код на CoffeeScript:
square = (x) -> x * x
cube   = (x) -> square(x) * x

Его JavaScript-эквивалент:
(function() {
	
var cube, square;

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

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

}).call(this);

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

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

Далее обратим внимание, что объявления всех локальных переменных var cube, square вынесено в начало. Что защищает от распространенной ошибки, когда переменная не с того, не с сего стала глобальной из-за того, что банально забыли добавить объявление var.

Стрелочка -> заменяет слово function.
И еще обратите внимание, что нет необходимости добавлять слово return. Оно добавляется автоматически к последнему выражению в функции.

Значения параметров по умолчанию

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

Пример на CoffeeScript:
fill = (container, liquid = "coffee") ->
  "Filling the #{container} with #{liquid}..."

Эквивалент на JavaScript:
var fill;

fill = function(container, liquid) {
  if (liquid == null) {
    liquid = "coffee";
  }
  return "Filling the " + container + " with " + liquid + "...";
};

JavaScript-реализация сводится проверке параметра liquid на равенство null или undefined.
Другая деталь, которую иллюстрирует пример — в качестве выделения блоков используются не фигурные скобки, а отступы, как в Питоне.

Итерация свойств объекта

Другая вещь, которая раздражает в JavaScript — очень многословная итерация по свойствам объектов.
Дело в том, что в большинстве случаев при обходе объекта интересуют его собственные свойства, а не свойства прототипа.
А делать каждый раз for а в нем сразу же проверку hasOwnProperty немного утомляет.
Решение же в стиле jQuery.each() никто не запрещал, но оно уступает по эффективности дедовскому for.

Смотрим, как сделать круто:
yearsOld = max: 10, ida: 9, tim: 11

for own child, age of yearsOld
  console.log "#{child} is #{age}"  

Эквивалент:
var age, child,
  __hasProp = {}.hasOwnProperty;

for (child in yearsOld) {
  if (!__hasProp.call(yearsOld, child)) continue;
  age = yearsOld[child];
  console.log("" + child + " is " + age);
}

Приятные мелочи

В JavaScript оператор == ведет себя мягко говоря странно. Гораздо безопаснее использовать ===. Поэтому CoffeeScript преобразует оператор == в ===, оберегая начинающих разработчиков от подстерегающих в JavaScript ловушек. Хотя приходит в голову один случай, когда оператор == все-таки полезен. Это сравнение с null, которое позволяет проверить null и undefined одним махом. В CoffeeScript для этого предназначен оператор ?. Рассмотрим пример:
alert "I knew it!" if elvis?

И на выходе:
if (typeof elvis !== "undefined" && elvis !== null) {
  alert("I knew it!");
}   

Классы

Переходим к классам. На всякий случай уточним, что классами будем называть функции-конструкторы объектов.

Рассмотрим пример:
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()

Даже интуитивно можно догадаться, что происходит. Описаны базовый класс Animal и два его наследника: Snake и Horse.
Обратим внимание на класс Animal. Запись @name в параметрах конструктора — это удобное сокращение, которое определяет свойство класса name и автоматически присваивает ему значение, передаваемое в конструкторе. В методе move запись @name — сокращение от this.name.

В методах move в подклассах super вызывает родительский метод с тем же названием. Ведь, и правда, когда мы находимся в дочернем классе, ссылка на родителя бывает нужна только для того, чтобы обратиться к одноименному методу родительского класса. Другие случаи даже в голову не приходят.

Не буду томить и, наконец-то, перейдем к js-варианту наших классов.
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();

В основе наследования лежит вариация классической функции extend.
Реализация достаточно простая. Конечно, если сравнивать с другими JavaScript библиотеками, которые предоставляют удобную кросс-браузерную реализацию классов на чистом JavaScript.
Минус навороченных библиотек в том, что не всегда легко разобраться, как они работают внутри.
А функция extend очень хорошо описана во множестве источников, например, здесь javascript.ru/tutorial/object/inheritance#nasledovanie-na-klassah-funkciya-extend.

Эффективность

Еще достаточно важный критерий — эффективность генерируемого кода. Так вот, с этим все в порядке, никаких глупостей я не обнаружил. Функции как положено добавляются не как свойства класса, а в прототип. Также порадовало, что значение по умолчанию свойств класса тоже добавляются в прототип.

Рассмотрим очень простой класс:
class Foo
  bar: 10

На выходе имеем JavaScript:
var Foo;

Foo = (function() {
	function Foo() {}
	Foo.prototype.bar = 10;
	return Foo;
})();

Здесь используется, так называемая асимметричность свойств объекта на чтение и на запись.
В реальной жизни значение свойства по умолчанию практически всегда выгодней добавлять в прототип объекта.
Пока нам не понадобится изменить это значение по умолчанию, мы не тратим лишнюю память для каждого объекта определенного класса. Но, допустим, мы решили изменить значение данного свойства так:
obj = new Foo() 
obj.bar = 500

Здесь создается персональное свойство bar у объекта obj. При этом свойство bar прототипа объекта obj по-прежнему равно 10. Все безопасно и эффективно.

Единственное, что может смущать в этом подходе, что при обращении к свойству, которое находится в прототипе, приходится продвигаться по цепочке прототипов. А это дается не бесплатно. Но на современных движках это не существенно, тем более на фоне радикальной оптимизации использования памяти, ну а старые IE-ки, в которых ощущалась деградация, постепенно уходят в небытие.

Назначение обработчиков событий

Другая крутая фича — назначение обработчиков событий для методов объектов. Пример:
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);
  });
};

Чтобы в качестве обработчика события указать метод этого же объекта на чистом JavaScript, приходится выкручиваться.
Один из самых распространенных способов — создание замыкания. В CoffeeScript этот костыль не нужен. Достаточно функцию обработчика указать не как ->, а =>. После этого this внутри обработчика будет ссылаться на базовый объект.

Интеграция с чистым JavaScript

Если потребуется подключить чистый JavaScript-код, то это также просто сделать:
hi = `function() {
  return [document.title, "Hello JavaScript"].join(": ");
}`

На выходе получаем:
var hi;

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

Массивы

Ну и конечно, присутствует много фишек для работы с массивами и объектами. Для иллюстрации рассмотрим одну.
Например, пусть мы хотим получить массив кубов чисел от 1 до 5.

В CoffeeScript достаточно написать:
cubes = (Math.pow(num, 3) for num in [1..5]) 

В многословном JavaScript получаем:
var cubes, num;

cubes = (function() {
  var _i, _results;
  _results = [];
  for (num = _i = 1; _i <= 5; num = ++_i) {
      _results.push(Math.pow(num, 3));
  }
  return _results;
})();

Заключение


Надеюсь, для знакомства должно хватить. Дальше добро пожаловать на coffeescript.org.

Ну и как положено, несколько выводов:
  • CoffeeScript увеличивает выразительность кода, упрощает и ускоряет как первоначальную разработку, так и дальнейшую поддержку кода.
  • Обучение очень быстрое (мне хватило пару дней втянуться).
  • Удобная поддержка со стороны WebStorm (Для других IDE тоже есть плагины, но про их качество ничего не могу сказать)
  • Большое community
  • Уберегает особенно начинающих разработчиков от многих ошибок.

Главное — понимать, что генерирует CoffeeScript. Тогда он превращается из лишнего подозрительного слоя абстракции в мощный инструмент.
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с habrahabr.ru

1

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • habrahabr.ru
          • домен habrahabr.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции