yo_waka's blog

418 I'm a teapot

最近のJavaScriptモジュールの書き方

サーバサイド(特にNode.js)とクライアントサイド両方で動かしたいものは最近はこんな感じで書いている。
CommonJSのwiki見ててそこに紹介されてるソースコードで(どれだったか忘れたけど。。)やってたのを見ていいなーと思って真似っこした。

(function(define) {
define([], function() {

    'use strict';

    /**
      * @constructor
      */
    var SomeClass = function() {
        // initialize
    };

    /**
      * @type {string}
      * @private
      */
    SomeClass.prototype.hoge_ = 'hoge';

    /**
      * @return {string}
      */
    SomeClass.prototype.getHoge = function() {
        return this.hoge_;
    };

    return SomeClass;
});
})(typeof define !== 'undefined' ?
    // use define for AMD if available
    define :
    // If no define, look for module to export as a CommonJS module.
    // If no define or module, attach to current context.
    typeof module !== 'undefined' ?
    function(deps, factory) { module.exports = factory(); } :
    function(deps, factory) { this['SomeClass'] = factory(); }
);

"define"は、AMD(Asynchronous Module Definition)として非同期に依存関係のあるライブラリを読み込むAPIAMDはCommonJSでもPROPOSALになっている。RequireJSとか使ってるとこっちで読み込む。
AMDに対応していないモジュール機構(Node.jsやCommonJSのModules1.1とか実装してるライブラリ)を使ってるならmodule.exportsが使われる。
それも使ってなくて普通にscriptタグに書いて使う分にはグローバル変数に名前を定義する。

もしライブラリ作ってて、後から名前変えたい場合もthis['AnyClass'] = factory();とかすれば簡単に変えられるし、プライベート変数も定義しやすくてなるほどなーと思った。
1ファイルにつき1クラス(オブジェクト)が返るというのもモジュールの見通しがよくなっていいと思う。

もちろん名前空間パッケージごとにきっちり区切ってやんなきゃいけないような大規模な感じだと、ClosureLibraryみたいな別のやり方でやった方がいいと思う。