HTML5Experts.jp

モダンな言語でHTML5を開発しよう! 俯瞰して理解するaltJSの比較 (前篇 – TypeScript, CoffeeScript, Haxe)

ここ数年のHTML5やCSS3の劇的な進化に比べて、JavaScriptの言語としての進化は緩やかだったのではないでしょうか。HTML5の登場により、リッチなウェブサイト・コンテンツ・アプリケーションが求められる時代になったのに、それを制御する言語が未だにレガシーなものであり、ニーズに追いついていないのが現状です。

2010年前後からこれらを解決する手段として、JavaScriptを生成する中間言語が登場してきました。これらはJavaScriptの代替ということで「altJS」と呼ばれています。altJSの言語の多くはクラス機構のサポートなどJavaScriptの抱える問題の多くを解決しており、スマートにコードを書くための仕組みが用意されており、開発効率を大幅に向上させることができます。本記事では前後編の2回でaltJSの5種類の言語を比較します。

はじめに

altJSとしてよく知られているのが次の5つの言語です。これらの複数の選択肢から、どの言語を選択するかは悩みどころです。例えば静的型情報やコンパイル時の型チェックの有無、パフォーマンス、既存JSとの相性、記述を要するコード量、開発環境の充実度など、言語を採用するには様々な観点からバランスよく選択することが重要になってきます。

本記事では各言語の基本的な文法や特徴、開発環境、筆者が考えるメリット・デメリットについて紹介します。

言語 設計/開発 登場時期 影響を受けた言語
CoffeeScript Jeremy Ashkenas, et al. 2009 JavaScript, Python, Ruby, Haskell
TypeScript Microsoft 2012 JavaScript, Java, C#
Haxe Haxe Foundation,
Nicolas Cannasse
2005 ActionScript, OCaml
Dart Google 2011 Java, C++, JavaScript, CoffeeScript, Go
JSX DeNA 2012 JavaScript, ActionScript

※いずれの言語もマルチプラットフォームであり、Windows, Mac OS Xともにどちらでも利用することができます。

比較対象のサンプル

サンプルとしてシンプルなスライドショーのWebコンテンツを用意しています。それぞれの言語でどのように記述して実装するのか、また生成されたJavaScriptがどのようなものであるか確認していきましょう。このサンプルでは言語の特性を紹介するために、実用的な要素として「クラス構造の利用」「既存JSライブラリの利用」「ユーザー操作」を含めています。

「Change Photo」ボタンをクリックすると写真が切り替わります。CSS3の3D TransformsをjQueryを用いて制御します(確認の際には、CSS3の3D Transformsが利用できるブラウザをご利用下さい)

TypeScript

概要

TypeScriptはマイクロソフトが開発するオープンソースの言語です。TypeScriptはJavaScript/ECMAScript 5を拡張した設計となっており、型情報やクラス、インターフェース、module、アロー関数式、列挙型、ジェネリクスといった言語機能が搭載されています。また既存のJavaScriptに僅かな修正を加えるだけでTypeScriptとして動作させることも可能です。いつくかの構文はECMAScript 6の案をベースとしたものになっています。

出力されたJavaScriptコードはとても読みやすく、TypeScriptのコードと基本的に1対1対応しています。またコメントも含めてJSに出力されるためデバッグが容易です(ソースマップを利用したデバッグも可能です)。

既存JSライブラリの使用方法

TypeScriptでは定義ファイル(拡張子は.d.ts)と呼ばれるインターフェースを定義したファイルを用意します。TypeScriptではreferenceタグという記述で定義ファイルを参照します。有名なJSライブラリの定義ファイルはborisyankov/DefinitelyTypedでまとまっているので、ここからダウンロードすると良いでしょう。

:javascript:
/// 

コード例

TypeScriptのコード(v0.9.1.1)

基本的な文法は既存のJavaScriptと同じです。変数には「:」キーワードで任意に型情報を記述することができ、クラスではアクセス修飾子の「private」を利用することで外部から参照することのできないメンバー変数や関数を用意することができます(カプセル化が可能)。

:javascript:
///     
window.onload = ()=> {
    var countManager:CountManager = new CountManager();

    $("#btn").click(()=> {
        // カウントを更新
        countManager.addCount();
        // CSSの角度を計算
        var rot:number = countManager.getCount() * 90;
        // エレメントに適用
        $("#effect").css("transform", "rotateX(" + rot + "deg)");
    });
}

class CountManager {
    private _count:number = 0;
    constructor() {
    }
    addCount() {
        this._count++;
    }
    getCount() {
        return this._count;
    }
}

TypeScriptをコンパイルして生成したJavaScriptのコード

生成されたJavaScriptがオリジナルのTypeScriptの原型をとどめたまま出力されているのがわかります(日本語を含むコメントアウトまで出力されてます)。

:javascript:

///     
window.onload = function () {
    var countManager = new CountManager();

    $("#btn").click(function () {
        // カウントを更新
        countManager.addCount();

        // CSSの角度を計算
        var rot = countManager.getCount() * 90;

        // エレメントに適用
        $("#effect").css("transform", "rotateX(" + rot + "deg)");
    });
};

var CountManager = (function () {
    function CountManager() {
        this._count = 0;
    }
    CountManager.prototype.addCount = function () {
        this._count++;
    };
    CountManager.prototype.getCount = function () {
        return this._count;
    };
    return CountManager;
})();
//# sourceMappingURL=main.js.map

開発環境

コンパイラを無償でダウンロードできるので、基本的にエディターは選びません。開発環境としてはVisual StudioやWebStorm/IntelliJ IDEAが対応しており、これらのソフトでコード補完やリファクタリング機能を利用することができます。既存のJavaScriptと比べて型指定や型推論も利用できるため、エディターによっては強力なコード補完の恩恵を受けることが可能です。

Visual StudioでTypeScriptを開発している様子

筆者が考えるTypeScriptのメリットとデメリット

メリットとしてはJavaScriptを習熟した人であれば、差分を学習するだけで利用できる学習コストの低さや、型情報や数多くの機能が言語に搭載されており、安全かつ効率的に開発できる点です。出力するファイルを分割することも一つにまとめることもでき、柔軟な開発スタイルが提供されています。またECMAScript 6の案を先行実装している点からも、将来標準になる言語を学習している安心感があります。

デメリットとしてはコンパイルが遅いことと、クラスのメンバー参照で必ずthisを記述しないといけない点、モジュールを利用した場合の名前空間の記述が煩雑になる点です(import修飾子が使えるものの根本的な解決になってはいない)。こういったメリット・デメリットから、JavaScriptエンジニアが中・大規模な開発プロジェクトに利用するのに向いているのではないかと考えています。

CoffeeScript

概要

CoffeeScriptはJavaScriptに比べてシンプルに記述できるため、コード量が少なくなり可読性の高いコードを記述できる言語です。クラス機構をサポートしているほか、配列内包やパターンマッチを利用することができます。構文はRubyライクでもあり、Ruby on Rails 3.1でも正式にサポートされています。

既存JSライブラリの使用方法

どのJSライブラリでも、基本的には設定を要せず利用することが可能です。TypeScriptやHaxeのような定義ファイルを用意する必要はありません。

コード例

CoffeeScriptのコード (v1.6.3)

インデントやシンタックスシュガーを利用する文法の恩恵もあり、他のaltJSのサンプルと比べて最も少ないコード量となっています。TypeScriptと同様にアロー関数式を使うことができたり、「@」キーワードを使えることでthisの指し示すスコープがわかりやすいのが特徴でしょう。またパターンマッチングが利用できるため、①の箇所のように、文字列の中に変数を埋め込むことが可能です。

:javascript:
window.onload = ->
  countManager = new CountManager

  $("#btn").click ->
    # カウントを更新
    countManager.addCount()
    # CSSの角度を計算
    rot = countManager.getCount() * 90
    # エレメントに適用
    $("#effect").css("transform", "rotateX(#{rot}deg)") #①

class CountManager
  _count: 0

  addCount: ->
    @_count++

  getCount: ->
    return @_count

CoffeeScriptをコンパイルして生成したJavaScriptのコード

CofeeScriptもオリジナルのコードが素直にJavaScriptとして出力されています。回避策はありますが、関数の最後の行がreturnステートメントで返されているところは少し戸惑うかもしれません。

:javascript:
// Generated by CoffeeScript 1.6.3
(function() {
  var CountManager;

  window.onload = function() {
    var countManager;
    countManager = new CountManager;
    return $("#btn").click(function() {
      var rot;
      countManager.addCount();
      rot = countManager.getCount() * 90;
      return $("#effect").css("transform", "rotateX(" + rot + "deg)");
    });
  };

  CountManager = (function() {
    function CountManager() {}

    CountManager.prototype._count = 0;

    CountManager.prototype.addCount = function() {
      return this._count++;
    };

    CountManager.prototype.getCount = function() {
      return this._count;
    };

    return CountManager;

  })();

}).call(this);

開発環境

コンパイラを無償でダウンロードできるので、基本的にエディターは選びません。開発環境としてはVisual StudioやWebStorm/IntelliJ IDEAが対応しています。

WebStormでCoffeeScriptを開発している様子

筆者が考えるCoffeeScriptのメリットとデメリット

メリットとしては、圧倒的なコード記述量の少なさです。JavaScriptのシンタックスシュガーと呼ばれるように、最小限のタイピングでどんどんコードがかけていく魅力があります。またインデントを利用する言語であることから、コードの可読性が必然的に高くなるのもメリットの一つです。

デメリットとしては型情報がないことによる、静的型チェックが無いことや開発環境でのコード補完利用の限界です(型情報がないとコード補完にノイズが入りがちになります)。こういったメリット・デメリットから少人数・小規模な体制でスピーディに開発する場合に向いているのではないかと考えています。

Haxe

概要

Haxe(ヘックス)は静的型付け(ただし動的型も使用可能)のオブジェクト指向言語です。汎用プログラム言語でありJavaScriptの他にも、ActionScript、C++、C#、Java、PHPへのソースコードの変換が可能です。

Haxeは文法としては標準化が中止されたECMAScript 4に類似しており、Flashの開発言語ActionScript 3.0に似ているのが特徴です。数多くの機能を言語レベルで備えており、クラス/パッケージ機構、型推論、ジェネリクス、インライン関数、パターンマッチング、配列内包表記、構造的サブタイピング、高機能な列挙型(詳しくは[公式サイトの説明]を参照ください)等の機能を持ち合わせています。コンパイラがOCamlという言語で開発されており、コンパイルが高速です。言語としての硬さ(厳密な型のチェック)やコンパイル速度の面から、大規模開発においてメリットがあります。

既存JSライブラリの使用方法

Haxeでは、Externと呼ばれるインターフェースを定義したファイルを用意します。Externファイルは自分で作成することも可能ですが、Haxe専用のパッケージ管理ツール「haxelib」を使うことで著名なJSライブラリのExternファイルをインスントールすることができます。

例:CreateJSのインストール方法 haxelib install createjs

コード例

Haxeのコード (Haxe 3.0)

HaxeはJavaScriptだけがターゲットの言語ではないため、JSのwindowオブジェクトにアクセスするには、Browserクラスのwindowプロパティを参照します。JavaScriptのオブジェクトを呼び出す際にはこういったラッパークラスを経由して呼び出す必要があります。jQueryを利用する場合は「new JQuery()」という形でインスタンスを作成して利用します。使い方は大きく異ならないもののHaxeの言語文化にあった形にライブラリのAPIが整理されている場合があるので注意が必要です。

:javascript:
package ;
import js.Browser;
import js.JQuery;

class Main {    
    static function main() {
        new Main();
    }

    function new () {
        Browser.window.onload = init;
    }

    function init(e:Dynamic){
        var countManager:CountManager = new CountManager();

        new JQuery("#btn").click(function():Void {
            // カウントを更新
            countManager.addCount();
            // CSSの角度を計算
            var rot:Int = countManager.getCount() * 90;
            // エレメントに適用
            new JQuery("#effect").css("transform", "rotateX(" + rot + "deg)");
        });
    }
}

class CountManager {
    private var _count:Int = 0;
    public function new () {
    }
    public function addCount():Void {
        _count ++;
    }
    public function getCount():Int {
        return _count;
    }
}

Haxeをコンパイルして生成したJavaScriptのコード

Haxeでは、ECMAScript 5相当のJavaScriptを出力します。比較的読みやすいコードが出力されますが、下記の例ではBrowserオブジェクトやJQueryオブジェクトなど、ラッパーオブジェクトがそのままJavaScriptとして出力されています。出力されたコードは手を加えるのはあまり向いていないと言えるでしょう。

:javascript:
(function () { "use strict";
var Main = function() {
    js.Browser.window.onload = $bind(this,this.init);
};
Main.main = function() {
    new Main();
}
Main.prototype = {
    init: function(e) {
        var countManager = new CountManager();
        new js.JQuery("#btn").click(function() {
            countManager.addCount();
            var rot = countManager.getCount() * 90;
            new js.JQuery("#effect").css("transform","rotateX(" + rot + "deg)");
        });
    }
}
var CountManager = function() {
    this._count = 0;
};
CountManager.prototype = {
    getCount: function() {
        return this._count;
    }
    ,addCount: function() {
        this._count++;
    }
}
var js = {}
js.Browser = function() { }
var $_, $fid = 0;
function $bind(o,m) { if( m == null ) return null; if( m.__id__ == null ) m.__id__ = $fid++; var f; if( o.hx__closures__ == null ) o.hx__closures__ = {}; else f = o.hx__closures__[m.__id__]; if( f == null ) { f = function(){ return f.method.apply(f.scope, arguments); }; f.scope = o; f.method = m; o.hx__closures__[m.__id__] = f; } return f; };
var q = window.jQuery;
js.JQuery = q;
js.Browser.window = typeof window != "undefined" ? window : null;
Main.main();
})();

開発環境

コンパイラを無償でダウンロードできるので、基本的にエディターは選びません。開発環境としてはFlashDevelopの対応が特に充実しており、非常に強力な「あいまい補完」と言われるコード補完や、コード生成機能を利用することができます。

FlashDevelopでHaxeを編集している様子

筆者が考えるHaxeのメリットとデメリット

メリットとしては、数多くの機能を言語レベルで搭載している点や、コンパイルが高速である点です。JavaScriptの名前空間の煩雑さやthisのスコープの苦労がなくなるのも大きなメリットの一つです。

デメリットとしては、言語が厳密過ぎる点です。基本的に型指定は必須ですし、暗黙的な型変換が利用できないので、慣れないうちはコンパイルエラーに苦労するでしょう。また出力されるJSファイルが一つにまとまることから、モジュール開発(JSライブラリ開発)には向いていないでしょう。

こういったメリット・デメリットから、大規模もしくはゲームや全画面Canvasのコンテンツなど、複雑なコンテンツを安全に開発する場合に向いているでしょう。  

まとめ

私がaltJSを選ぶ際に必要と考えるのは、プロジェクトへの適正と、エンジニア/クリエイターのバックグラウンドだと考えています。それぞれのaltJSに影響を受けた言語があるように、開発に従事するエンジニアのバックグラウンドによって、言語のとっつきやすさに差があると思います。具体的にはRubyユーザーにはCoffeeScriptが、FlashユーザーにはHaxeが向いている傾向があるでしょう。利用するユーザーが様々なのでaltJSがどれか一つの言語に収束することはなく、勢力分布の変化はあれど基本的にはaltJSのユーザー数は並行して進化していくと筆者は考えています。

次回の後編では、altJS言語としてDartとJSXを紹介します。

参照