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;
}