CoffeeScriptを使う理由

  • 645
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

随時更新します。

  1. CoffeeScriptを使う理由
  2. TypeScriptを使う理由
  3. AltJSを使わない理由
  4. Dartを使う理由

仕事でCoffeeScriptを使う場合の説得材料まとめです。

なぜJavaScriptではいけないのか

クラス定義がないからです

みんな大好きオブジェクト指向をするために必須なのにJavaScriptではクラスは書けません。
いや、正確には書けます。

クラス定義
function Person() {};

なんだクラスは簡単に書けるじゃないかと思いましたか?


クラス定義その2
function Person() {
  this.name = "takashi";
  this.age = 20;
};
Person.prototype.echo = function () {
  return "Hello " + this.name + " !!";
};

コンストラクタ、メソッドを書いただけで、コード量が増えてきましたね。
毎回クラス名とprototypeと書く必要があります。
めげてきましたか?
私はめげてます。


次は継承してみましょう。

継承
function inherits(ctor, superCtor) {
  ctor.super = superCtor;
  ctor.prototype = Object.create(superCtor.prototype, {
    constructor: {
      value: ctor,
      enumerable: false,
      writable: true,
      configurable: true
    }
  });
};

inherits(Employee, Person);
function Employee() {
  Person.apply(this, arguments);
};

Employee.prototype.echo = function () {
  return "Hello " + Employee.super.prototype.echo.call(this);
};

どうでしょうか?
継承元を呼び出すのにEmployee.super.prototype.echo.call(this)のように書かないといけません。

継承の方法は今まで迷走していたので各々実装方法も違います。
詳しく知りたい場合はこちらを参照するといいです。
そんな継承はイヤだ - クラス定義 - オブジェクト作成

勘違いしてしまうfor文

以下のコードは間違っています。

間違ったfor...in
var ary = [100, 200, 300];
for (var i in ary) {
  console.log(i);
}

JavaScriptでinは配列のeachではありません。
オブジェクトのプロパティ名をeachする命令です。

正しいfor...in
var obj = {key1: 100, key2: 200, key3: 300}
for (var key in obj) {
  console.log(obj[key]);
}
正しい配列のfor
var ary = [100, 200, 300];
for (var i = 0 ; i < ary.length ; i++) {
  console.log(ary[i]);
}

functionという記述が長過ぎる

JavaScriptはシングルスレッドなので、callbackを多用します。
多用するのに毎回functionと書かなければいけません。
後からコードを見直すとfunctionだらけで頭が痛くなることでしょう。

functionが長過ぎる
var self = this;
$.get("/users", function (users) {
  var result = [];
  $.each(users, function (user) {
    result.push(new User(user));
  });
  return result;
}).done(function (users) {
  self.users = users;
}).fail(function (xhr, status, msg) {
  console.error(msg);
});

グローバル汚染を防ぐためにすることがある

functionで命令を閉じ込めてあげないとグローバルに定義されるので
他のライブラリとぶつかったりします。

varを書き忘れるとグローバルになるので他のライブラリと・・・

グローバル汚染をする?しない?
// グローバル汚染します
function Person() { // グローバル汚染
  name = "takashi"; // グローバル汚染
  this.word = "Hello " + name + " !!"; // でも動くよ
}
new Person();
name; // -> takashi

// グローバル汚染しません
(function () {
  function Person() {
    var name = "takashi";
    this.word = "Hello " + name + " !!";
  }
  new Person();
})();
name; // undefined

比較が曖昧

比較時に勝手に変換すると予期せぬ挙動となります。
なので毎回===と書かなくてはいけない。

比較例
""           ==   "0"           // false
0            ==   ""            // true
0            ==   "0"           // true
false        ==   "false"       // false
false        ==   "0"           // true
false        ==   undefined     // false
false        ==   null          // false
null         ==   undefined     // true
" \t\r\n"    ==   0             // true

CoffeeScriptを使おう

これらのよくないコードを未然に防いでくれるのがCoffeeScriptです。
それぞれ例をみていきましょう。

クラス定義
class Person
  constructor: () ->
    @name = "takashi"
    @age = 20

  echo: () ->
    "Hello #{@name} !!"

class Employee extends Person
  constructor: () ->
    super

  echo: () ->
    "Hello #{super()}"
for文
# 配列のループ
ary = [100, 200, 300]
for value in ary
  console.log value

# プロパティのループ
obj = {key1: 100, key2: 200, key3: 300}
for key, value of obj
  console.log(value)
function文
$.get "/users", (users) =>
  result = [];
  $.each users, (user) =>
    result.push(new User(user))
  return result
.done (users) =>
  @users = users
.fail xhr, status, msg =>
  console.error(msg)
グローバル汚染しない
# CoffeeScriptコンパイル時にbare=trueで関数で囲んでくれる
class Person
  constructor: () ->
    @name = "takashi" # インスタンス変数
    @word = "Hello #{name} !!" # ローカル変数
}
new Person()
name # -> undefined
比較は厳密
""           ==   "0"           # false
0            ==   ""            # false
0            ==   "0"           # false
false        ==   "false"       # false
false        ==   "0"           # false
false        ==   undefined     # false
false        ==   null          # false
null         ==   undefined     # false
" \t\r\n"    ==   0             # false

どうですか?
ダメなコードも未然に防げて、かつ簡素なコードでしょう?

CoffeeScriptはコンパイルしてJavaScriptを出力するけど、デバッグはどうするの?

CoffeeScriptにはSourceMapを出力するオプションが存在します。
これは出力されたJavaScriptがCoffeeScriptのどのコードの位置とマッチするかの情報を含んだファイルです。
これをChromeに食わせることにより、CoffeeScriptでデバッグが行えます。

詳しいやり方はグーグルでCoffeeScript source map chromeとかで検索するといいです。

ですが私が今までCoffeeScriptで開発してきた経験からいうと、出力されたJavaScriptをそのままデバッグした方が楽にデバッグできます。

CoffeeScriptが何行かのJavaScriptを出力しているために、同じ行でデバッガーのNext Stepを何回する必要があるため、変なところで進んだり止まったりしてデバッグしにくいです。

consoleにそのままCoffeeScriptを貼付けて動作させることもできないので、わざわざ変換するのが面倒だったりします。
CoffeeConsole?あれは忘れた方がいい。

CoffeeScriptは別言語なのではなく、JavaScriptのシンタックスシュガーです。
CoffeeScriptとJavaScriptの命令は1対1で簡単に結びつきます。
なので出力されたJavaScriptで苦もなくデバッグすることができます。

ちょっと注意、魔法の杖ではありませんよ。

HibernateしかりActiveRecordしかり、ORMはDBの設計、SQLをある程度知っていて始めて使用することができます。
ORM使うからSQL知らなくても問題ないぜー!!バリバリー!!
みたいなことはしてませんよね?

CoffeeScriptもご多分に漏れずJavaScriptをある程度知っている必要があります。
いきなりCoffeeScriptから始めます!
というようなことは避けた方が懸命です。
JavaScriptを軽く学習させてからCoffeeScriptを学習させてください。
そうしないとデバッグで死にます。

わかりました。CoffeeScriptを使います。

ようこそCoffeeScriptの世界へ。

あたなはCoffeeScriptを採用したことで以下の恩恵を受けることができます。

  1. ソースコードが簡素になったことで保守性があがります。
  2. JavaScriptの罠に嵌らなくなります。

あれ?少ない?
いえいえ、すごく大事な2点です。
塵積です。

でも待って・・・実は問題山積みなんです。

CoffeeScriptはコンパイルが必要です。
このコンパイルを甘く見てはいけません。

やってみればわかります。めんどいです。

私もCoffeeScriptコンパイルジプシーです。

・・・この投稿はとりあえずここまで!!
次回私が行ったCoffeeScriptのコンパイル方法の変遷を紹介します。

書きました。
私のCoffeeScriptをコンパイルする方法の変遷