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