Google流 JavaScript におけるクラス定義の実現方法
http://www.yunabe.jp/docs/javascript_class_in_google.html
ちょっと便利なJavascriptオブジェクトの作り方
http://blog.asial.co.jp/iphone/1101
ちょっと便利なJavascriptオブジェクトの作り方
今回は、ちょっと便利なJavascriptオブジェクトの作り方をご紹介します。いわゆるモジュール・パターンと呼ばれている方法です。
はじめに
最近、HTML5への注目と共に、Javascriptを使用する機会が増えてきました。以下のように適用範囲は多岐に渡っています。
通常のWebサイトでのユーザビリティ向上
スマートフォン用Webサイト開発
HTML5アプリによるクライアント・アプリ開発
スマートフォンのハイブリッドアプリ開発
Node.jsによるサーバサイド・プログラミング
このように、Javascriptが基幹となる仕組みが広がっています。クライアント側とサーバ側を同じ言語で作れることは、開発側にとってはとても有難いことです(学習コストの低減、人的リソース配分の柔軟性など)。もちろん、発注者やエンドユーアにとっても開発速度などの面で利益が生まれます。
Javascriptプログラミングを行う上で必須なのが、オブジェクトの作り方と活用です。従来、Javascriptといえばグローバル変数や関数を多用したプログラミングがなされていました。しかし今日では、Javascriptの使い方も洗練されてきており、オブジェクトを中心としたコードが一般的です。今後、Javascriptの開発をするには、オブジェクトの作り方・使い方について詳しく知る必要があります。
オブジェクト・リテラル
一番簡単な作り方は、いわゆるオブジェクト・リテラルです。ハッシュ形式でオブジェクトを定義する方法です。
var Person = {
name: 'kazushi',
age : 36,
init: function() {
// 何らかの処理
},
getName: function() {
return this.name;
},
getAge: function() {
return this.age;
},
// オブジェクト内部でしか使わないメソッド
doSomething: function() {
...
}
};
// 初期化を実行
Person.init();
この方法は非常に簡単な反面、全てのプロパティを外部から変更可能です。例えば、
Person.name = 'hoge hoge';
Person.age = 0;
などと、プロパティの値を保障できなくなります。また、doSomething()メソッドを外部から実行できてしまいます。複数人での開発などでは意図しないバグを発せさせかねません。また、影響範囲を明確に定義できない問題があります。そのため、保守性が下がってしまいます。さらに、再利用時には、どのメソッドを使用すべきか迷うことも多々あります。
モジュール・パターン
モジュール・パターンはオブジェクトリテラルより断然お勧めです。プライベートメンバや公開API設定などが容易だからです(リテラルなど通常の作り方の場合、Javascriptではスコープ定義が難しいんですね)。
このパターンでは即時関数を利用します。Javascriptでは即時関数と言って、無名関数をその場で実行する方法があります。例えば、次のように記述します。
(function() {
var i;
for (i=0; i<10; i++) {
// 何らかの処理
}
}());
Javascriptのコードが読み込まれた際に、実行されます。何が便利かというと、変数のスコープを限定し(Javascriptでは変数のスコープが関数単位)、影響範囲を狭めることができます。コードが長くなる際には必須の仕組みです。
この即時関数を利用することで、オブジェクトのプライベートメンバ・メソッドや公開API設定を実施します。
var Person = (function(){
var _name = 'kazushi',
_age = 36;
function _init() {
// 何らかの処理
}
function _getName() {
return _name;
}
function _getAge() {
return _age;
}
function _doSomething() {
...
}
// 初期化を実行する
_init();
// 公開APIを返す
return {
getName: _getName,
getAge : _getAge
};
}());
ポイントは、即時関数内に変数と関数を定義し、最後に公開するものだけをオブジェクトで返している点です。こうすることで、_nameと_ageは外部から変更不可能となります。そして、Personオブジェクトの公開APIを設定でき、設計者の意図通りにこのオブジェクトを制限できます。ここでは_doSomething()関数を外部から実行することはできません。言葉を変えると、使う側は何を使えば良いかをすぐに理解できます。
また、公開APIの変更も簡単です(最後にreturnで返すオブジェクトを変更するだけですね)。
問題点としては、読み込まれた時点でスクリプトが実行される点です。巨大なオブジェクトや複雑な計算を即時関数内に入れて、実行してしまうと時間が掛かります。同時にメモリも消費します。とはいえ、よほどおかしなことをしない限り、実際には大した問題にはなりません。
おわりに
即時関数を用いたJavascriptオブジェクトの作り方は、他にもいろいろとあります。多くのフレームワークでは、即時関数内でオブジェクトを定義し、必要なものだけをwindowオブジェクトのプロパティに追加する方法を使用しています。ちょっとした工夫で、Javascriptをより楽しく便利につかうことは十分可能です。ぜひ試してみて下さい。
コメント
初めまして。
ちょうど最近、JSでのオブジェクト指向開発の方法を調べておりました。
モジュール・パターンはクラスを定義しないため、オブジェクトを即時に生成する方法としては手っ取り早くていいですね。
勉強させて頂きました。ありがとうございます。
ところで、モジュール・パターンのサンプルコードについてですが、
それぞれ最後の行のとじカッコ、正しくは「})();」だと思いますがいかがでしょうか。
by 鈴木健太 | 2012年11月20日 00:03
> 鈴木様
初めまして。
記事がご参考になり幸いです。
ご指摘ありがとうございます。
この部分については、どちらの書き方も使用可能です。
私も実は「})();」の書き方をよく使います。
今回は某書籍にならって「}());」を使ってみました。
by 井川数志 | 2012年11月20日 08:57
ザックリとしたオブジェクトの作り方の説明わかりやすくて参考になります。
>> }());
私もこれを本で見てからはこれを使うようにはしています。(正直、どちらでも問題ないと思います)
この書き方をしている本は私は2冊しかしらないですが。
私の記憶が正しければ、某書籍の某ダグちゃんは、これを使いなさいと、そうすればJS Lintも警告を出さないよ、的なことをおっしゃっていました。
by gatchang | 2012年11月20日 14:14
はじめまして
はてブより来ました。とても参考になる記事を有難うございます。
1つ質問ですが、モジュールパ・ターンで内部の変数名や関数名にアンダーバーを付けているのは
アンダーバー自体で振る舞いが変わるものではなく、「これ、プライベートですよ。外から見えないし使えませんよ」と
見やすくするという意味と思っているのですが当たっていますでしょうか?
by 中島 | 2012年11月20日 14:33
> gatchang様
私も書き方を知ってからは使うようにしています。ただ、慣れないうちは何となく違和感があり、ついつい"})()"を使っていました。
仰る通り、Douglasさんも某Stefanovさんも書籍では "}())" を使っています。"})()"はJSLintだと、「Move
the invocation into the parens that contain the
function.」とか何とか言われてしまいますね。
by 井川数志 | 2012年11月20日 15:54
> 中島様
はじめまして。
アンダーバーを付けている理由は仰る通りです。Javascriptでは変数のスコープが見えづらく苦労するため、可読性を上げるように気を付けています。変数を誤って使ってしまうと、グローバル変数を変えてしまったり、作ってしまったりと、とても恐いので。
個人的には、プライベートメンバとメソッドはアンダーバー開始、ローカル変数は通常の書き方、などとすることが多いです。
by 井川数志 | 2012年11月20日 16:00
prototypeは使わない派ですか?
by yu-yu | 2012年11月20日 20:42
> yu-yu様
もちろん必要に応じて使います(オブジェクトが複数になる場合など)。単一オブジェクトで処理できる場合には、上記の方法を使います。
by 井川数志 | 2012年11月21日 09:33
なるほど、そういうことだったのですね。
井川様、丁寧なお返事ありがとうございます!
by 鈴木健太 | 2012年11月22日 17:16
某書籍とは何でしょうか?
ググっても意味がでてこない・・・こんなことってめずらしい。
by 北村 | 2014年01月29日 10:52
某 書籍のことですね。とある書籍のことですね。。自己解決。すみませんでした。
by 北村 | 2014年01月29日 10:53
0 件のコメント:
コメントを投稿