作るのは数字だけじゃない / デジタルハリウッド
作るのは数字だけじゃない / デジタルハリウッド
2014.11.19

CoffeeScriptで記述量を減らし、スッキリしたソースにする方法

まろ

こんにちは、エンジニアのまろです。

キャラクターって大事ですよね。僕はクールに生きたいのに同僚がそうさせてくれません。だから今日はクールにcoffeeについて書いてみたいと思います。

もちろんCoffeeScriptのことです。

大人の飲み物のことではありません。僕はコーヒーの味の違いなんてわかりませんし、いつもカフェモカしか頼みませんからね。それではいってみましょう。

CoffeeScriptとは

CoffeeScriptとはaltJSの1つで、より短いコードでJavaScriptが書ける言語です。
スマートにコードを書くための仕組みが用意されており、開発効率を大幅に向上させることができます。クールですね。

他にもaltJSにはTypeScript、Haxe、Dart、JSXなどがありますが、単純に記述量が減らせ、型付けしたくないということでcoffeeを使うことにしました。

基本的にはCoffeeScriptで書いたものをJavaScriptに変換する手順が必要となるため、環境を作成し、最終的には開発に使えるようにgulpタスクに組み込んでいきます。

環境設定

まずはNode.jsを準備します。

インストールがまだという方は、こちらの記事「いまアツいJavaScript!ゼロから始めるNode.js入門〜5分で環境構築編〜」をご参照ください。

準備はこれだけです!

$ npm install -g coffee-script

hello coffee

さっそくCoffeeScriptで書いてコンパイルしてみましょう。

.coffeeファイルの作成

$ cd ~/coffee
$ vi common.coffee
#アラートを出すにはこんなかんじで書きます。
msg = "hello coffee"
alert msg
$ ls
common.coffee
#このディレクトリにはcommon.coffeeしかありませんね

コンパイル

$ coffee --compile ./
$ ls
common.coffee common.js
# common.jsファイルができてます!

Coffeeコマンドに--compileオプションをつけて./に出力するという意味です。

できあがったコードを見てみましょう

以下のとおりになります。

// Generated by CoffeeScript 1.8.0
(function() {
  var msg;

  msg = "hello coffee";

  alert(msg);

}).call(this);

詳細は後述しますが、書式の特徴として、varは付けません。コンパイル時に自動でvar付きで変数宣言されます。

文末のセミコロンもカッコも不要です。それなのに出力時には即時関数として書き出してくれます。

使うときはこれまでどおり、HTMLファイルでコンパイルした.jsファイルを読み込むようにすればいいわけです。

CoffeeScriptはここが便利

公式サイトの「TRY COFFEESCRIPT」にて、JavaScriptに出力されるコードと見比べながらCoffeeを試すことができます。

試してみよう

変数定義不要、文末のセミコロン不要、関数のカッコ不要です。

.coffee

msg = "hello coffee"
alert msg
console.log msg

.js

var msg;

msg = "hello coffee";

alert(msg);

console.log(msg);

 
ダブルクォーテーションで囲んだ中で変数展開可能です。

.coffee

msg = "coffee"
console.log "hello #{msg} script!"

.js

var msg;

msg = "coffee";

console.log("hello " + msg + " script!");

 
ヒアドキュメント(phperとして一番感動しました)

.coffee

title = "TITLE"
msg = "enjoy coffee."
out = """
<div>
  <h1>#{title}</h1>
  <p>#{msg}</p>
  <p>bye.</p>
</div>
"""

.js

var msg, out, title;

title = "TITLE";

msg = "enjoy coffee.";

out = "<div>\n  <h1>" + title + "</h1>\n  <p>" + msg + "</p>\n  <p>bye.</p>\n</div>";

 
if {}で囲むところはインデントでブロックと認識されます。英文章を書くイメージですね。

.coffee

num = 10
result = no
if num is 10
  yes
else if num isnt 10
  no

if num < 10
  console.log num
else if num > 10
  console.log num
else

.js

var num, result;

num = 10;

result = false;

if (num === 10) {
  true;
} else if (num !== 10) {
  false;
}

if (num < 10) {
  console.log(num);
} else if (num > 10) {
  console.log(num);
} else {

}

 
後置if。

.coffee

age = 20 if name is jiro

.js

var age;

if (name === jiro) {
  age = 20;
}

 
配列。

.coffee

datas = [1, 2, 3, 4, 5]
datas = [1..5]

.js

var datas;

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

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

 
さらにオブジェクト。

.coffee

obj = 
  name: "taro"
  age: 20

dobj = [
  {
    name: "jiro"
    age: 10
  }
  {
    name: "saburo"
    age: 70
  }
]

.js

var dobj, obj;

obj = {
  name: "taro",
  age: 20
};

dobj = [
  {
    name: "jiro",
    age: 10
  }, {
    name: "saburo",
    age: 70
  }
];

 
forはinかofを使います。

.coffee

for i in [0...10]
  console.log i

for data in datas
  console.log data

for key, value of obj
  console.log key, value

.js

var data, datas, i, key, value, _i, _j, _len;

for (i = _i = 0; _i < 10; i = ++_i) {
  console.log(i);
}

for (_i = 0, _len = datas.length; _i < _len; _i++) {
  data = datas[_i];
  console.log(data);
}

for (key in obj) {
  value = obj[key];
  console.log(key, value);
}

 
関数 ->がfunctionに相当。関数の最終行が自動的にreturnとなります。

.coffee

sum = (a, b) ->
  a + b

sum a,b

#関数 引数の初期値
hoge = (msg = "yo!") ->
  msg
#呼び出し
hoge()

.js

var hoge, sum;

sum = function(a, b) {
  return a + b;
};

sum(a, b);

hoge = function(msg) {
  if (msg == null) {
    msg = "yo!";
  }
  return msg;
};

hoge();

 
typeof undefinedも?で短縮できます。

.coffee

a = "coffee" if a?

.js

var a;

if (typeof a !== "undefined" && a !== null) {
  a = "coffee";
}

 
比較演算子と論理演算子

coffee => javascript

isnt は  !==
not    は !
and    は &&
or    は ||
true, yes, on は    true
false, no, off    は false
@, this    は this

となります。
公式リファレンスを見ると、コンパイル後のJavaScriptと見比べながらコードを見ることができるので、そちらご覧ください。

コードが短くスッキリしており、ワクワクが止まりません。カッコの数や、セミコロンのつけ忘れ、波カッコの終わりで頭を悩ますことがなくなります。

jQueryを使う

Web制作の場面で一番気になるのは、jQueryが使えるの? ということだと思います。答えは、使えます。以下のような感じで書けます。

.coffee

(($) ->
  $h1 = $("#wrapper").find "h1"
  message = "hello world"
  $window = $(window)

  $h1.text message

  $window.on "load", ->
    console.log "loaded!!"

  $(".page_top").on "click", (e) ->

    e.preventDefault()
    $("html, body").stop().animate
     scrollTop: 0
     , 500
    no

  yes
) jQuery

.js

(function($) {
  var $h1, $window, message;
  $h1 = $("#wrapper").find("h1");
  message = "hello world";
  $window = $(window);
  $h1.text(message);
  $window.on("load", function() {
    return console.log("loaded!!");
  });
  $(".page_top").on("click", function(e) {
    e.preventDefault();
    $("html, body").stop().animate({
      scrollTop: 0
    }, 500);
    return false;
  });
  return true;
})(jQuery);

gulpに組み込む

タスクランナーに組み込み、変更を監視してCoffeeScriptをJavaScriptで出力できれば、コンパイルコマンドの手間も省けます。
すでにgulpを使っている開発環境がある前提で、まずはモジュールをインストールします。

$ cd projectDir
$ npm install --save-dev gulp-coffee

タスクファイルに以下を追加して、監視対象にします。

$ vi gulpfile.js
var gulp = require('gulp');
var coffee = require('gulp-coffee');
〜〜〜中略〜〜〜
module.exports = function () {
    gulp.task('coffee', function () {
        return gulp.src('source/js/*.coffee')
            .pipe(coffee())
            .pipe(gulp.dest('assets/js'))
            .pipe($.browser.reload({stream: true}));
    });
}();

glupタスクもcoffeeで書いちゃう

glup自体もCoffeeScriptをはじめとするajtJSでのファイル構成をサポートしているので、そのまま書けます。

Coffee自体がないと動かないので、まずはいれましょう。

$ cd projectDir
$ npm install --save-dev coffee-script

今回は例として、先ほど作ったCoffeeのタスクをgulpfile.coffeeとして抜き出してCoffeescriptで書き換えます。
ファイル名はgulpfile.coffeeです。

gulp = require 'gulp'
$ = require('gulp-load-plugins')({
  pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del']
})
gulp.task 'coffee', ->
    gulp.src 'app/pc/source/js/*.coffee'
    .pipe $.plumber()
    .pipe $.coffee()
    .pipe gulp.dest 'app/pc/assets/js/', 'dest'

既存のgulpfile.jsはどこかに移動させ、CoffeeによるCoffeeためのgulpタスクを実行してみます。

$ gulp coffee

実行の仕方は同じです!
動いてます!

go_coffee

まとめ

Coffeeと同じように、多くを語らずに締めたいと思います。

  • 記述量が減ってスッキリしたソースに
  • 出力をイメージできるとガンガン書ける
  • trueなどはルールを決めたほうがよさそう

ちなみに次はVoltMeteorといった、かっこいい名前のフレームワークたちが気になっています! それでは。

. . .