classは、ECMAScript2015(ES6)で導入されましたが、 ECMAScript2015以前などの、classが使用できないJavaScriptでのクラス定義を行う方法。 厳密にはクラスと異なるのですが、クラスのように使用できます。 ただし、継承を利用できるようにすると難しくなるので、ここでは継承無しとします。

クラス定義は1ファイル1クラスとして、Node.jsでユニットテストができるようにします。 ユニットテスト用フレームワークmochaを使ったサンプルは以下になります。

継承なしクラス定義サンプル

クラス名をBookとすると以下のようになります。

(function() {
    /**
     * コンストラクタ
     */
    function Book(title) {
        this.title = title;
        this.author;
    }

    var p = Book.prototype;

    p.setTitle = function(title) {
        this.title = title;
    }

    p.getTitle = function() {
        return this.title;
    }

    p.setAuthor = function(author) {
        this.author = author;
    }

    p.getAuthor = function() {
        return this.author;
    }

    // Node.js(CommonJS)とHTML用の定義
    if (typeof exports === 'object') {
        module.exports = Book;
    } else {
        this.Book = Book;
    }
})();

概要

以下の箇所は、即時関数(IIFE: Immediately Invoked Function Expression)と呼ばれていて、定義するだけでなく即実行されます。 これは、定義部分のコードをグローバルスコープでなく、ローカルスコープにするために使用されます。

(function() {
...
})();

function Book(title)は関数定義ですが、new演算子でオブジェクトのインスタンスを作成すると、クラスのコンストラクターと同じように処理されます。 new演算子を使わない場合、これは通常の関数をして扱われるので、クラスとして使用したい場合は、必ずnew演算子でインスタンスを作成する必要があります。

p.xxx = function()... は、メソッドxxx の定義になります。 このサンプルでは、Book.prototypeを変数pとして、メソッド定義を簡略化していますが、以下のようにもできます。

    Book.prototype.setTitle = function(title) {
        this.title = title;
    }

以下の箇所の if 部分は、Node.js(CommonJS)のモジュールとして使用するための定義です。 else 部分は、HTMLで使用するための定義です。

    if (typeof exports === 'object') {
        // Node.js(CommonJS)用
        module.exports = [クラス名];
    } else {
        // HTML用
        this.[クラス名] = [クラス名];
    }

AMD(Asynchronous Module Definition)モジュールとしても使用する場合は、以下のように変更します。

Node.js(CommonJS)用定義

Node.js(CommonJS)で使用できるように定義している箇所は以下になります。

    if (typeof exports === 'object') {
        // Node.js(CommonJS)用
        module.exports = [クラス名];
    }

Node.jsで使用する場合、このクラス定義をファイルbook.jsとすると、以下のようになります。

var Book = require('Book.js');

// 定義したクラスの使用例
var book = new Book('タイトル');

HTML用定義

HTMLで使用できるように定義している箇所は以下になります。

    } else {
        // HTML用
        this.[クラス名] = [クラス名];
    }

HTMLで使用する場合は、HTMLファイルのscriptタグに直接書くか、別ファイルにする場合は、普通のJavaScriptファイルと同じように読み込みます。

<script type="text/javascript" src="/js/lib/Book.js"></script>

<script type="text/javascript>
    var book = new Book('タイトル');

    // 何か処理
</script>

AMD(Asynchronous Module Definition)モジュールで使用する場合

AMD(Asynchronous Module Definition)モジュールとしても使用する場合は、以下のようにします。

    if (typeof define === 'function' && define.amd) {
    	// AMD用
        define([], function() { return [クラス名]; });
    } else if (typeof exports === 'object') {
        // Node.js(CommonJS)用
        module.exports = [クラス名];
    } else {
        // HTML用
        this.[クラス名] = [クラス名];
    }

クラス名がBookの場合は、以下のようになります。

    if (typeof define === 'function' && define.amd) {
    	// AMD用
        define([], function() { return Book; });
    } else if (typeof exports === 'object') {
        // Node.js(CommonJS)用
        module.exports = Book;
    } else {
        // HTML用
        this.Book = Book;
    }