【追記】
記事末尾のコメントで指摘されているように、当記事の手法は、メモリ消費や処理速度においては不利な面がありますのでご注意ください。また、次期JavaScript(ES6)では正式に class が導入されます。
JavaScriptのクラスについては色々なサイトで解説されていますが、内部でthis
やprototype
を使用している形では、次のような危険性があります。
-
this
が外部と共有されるため、this
が自身のインスタンスではなくなることがある(特にメソッド内で外部系からのコールバックを使用している場合) -
prototype
を使ったメソッドがクラス内のローカル変数を参照している場合、その変数はインスタンス間で共有されるため、想定外の値になることがある(クロージャ効果)
以下、安全な書き方についてまとめてみました。
例)Itemクラス
// Itemクラス
var Item = function(name) {
// インスタンスとなるObject
var self = this;
// メンバー変数(public)
self.price = 0;
// ローカル変数(private的)
var _name = name;
// メソッド(public)
self.showInfo = function() {
alert(getInfo());
};
// ローカル関数(private的)
function getInfo() {
return _name + " is " + self.price + "yen";
}
};
var banana = new Item("Banana");
var orange = new Item("Orange");
banana.price = 100;
orange.price = 200;
banana.showInfo(); // "Banana is 100yen" が表示される
orange.showInfo(); // "Orange is 200yen" が表示される
長所
- クラス内のローカル変数がインスタンス毎に独立している(prototypeを使っていないため)。
- クラス内のメソッドで、ajaxなど、コールバックが発生する処理を実行しても安全(自身をselfで参照する限りは)。
短所
- インスタンス毎にメソッドが保持されるのでメモリ消費の点で不利(prototypeを使っていないため)。prototypeを用いる書き方は「やさしいクラスの作り方」が参考になります。
例)Appleモジュール(シングルトンもどき)
// Appleモジュール(即時関数を実行して生成)
var Apple = (function() {
var self = {}; // 自身の本体となるObject
// メンバー変数(public)
self.price = 0;
// ローカル変数(private的)
var _name = "Apple";
// メソッド(public)
self.showInfo = function() {
alert(getInfo());
};
// ローカル関数(private的)
function getInfo() {
var info = _name + " is " + self.price + "yen";
return info;
}
return self; // これ忘れないこと
})();
//var apple = new Apple(); // newはできない!
Apple.price = 300;
Apple.showInfo(); // "Apple is 300yen" が表示される
解説
JavaScript には正式なクラスがありません。そのかわり、new 演算子を使って function を object 化することで、クラスをインスタンス化するような使い方ができます。ただ、new や this の扱いが他言語とはかなり異なるため、上記のような書き方が比較的安全かなと思います。
Itemクラスのほうは、self
に登録したものだけがpublic
な感じでアクセスできます。Appleモジュールは、サイトによっては「モジュールパターン」として説明されています。こちらは即時関数によって object がreturn
されるので、new することはできません。
(・o・ゞ いじょー。
参考URL
【javascript】やさしいクラスの作り方
http://qiita.com/varmil/items/99fd6f2a886fdde4b7fa
ちょっと便利なJavascriptオブジェクトの作り方
http://blog.asial.co.jp/1101
Google流 JavaScript におけるクラス定義の実現方法
http://www.yunabe.jp/docs/javascript_class_in_google.html
JavaScript の new 演算子の意味
http://nanto.asablo.jp/blog/2005/10/24/118564
prototype と __proto__
http://d.hatena.ne.jp/cou929_la/20100929/1285770930
※__proto__は環境依存するようですのでご注意ください
Javascriptでプライベートメンバを使うなら、prototypeは諦める
https://sites.google.com/site/jun1sboardgames/programming/javascript-private-members
JavaScript の超便利なメソッド bind で this を制御する
http://foreignkey.jp/archives/763