主にプログラミングに関して。Python, .NET Framework(C#), JavaScript, その他いくらか。
記事にあるサンプルやコードは要検証。使用に際しては責任を負いかねます

スポンサーサイト

                
tags:
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

JavaScript: オブジェクト設計の技法 プライベート変数編

                
tags: JavaScript
 まえにオブジェクト指向とはどんなものかという説明をJavaScriptで展開した。
http://elicon.blog57.fc2.com/blog-entry-327.html

 ようはコーディングにおいて、特定の機能を一つのまとまりとしてオブジェクトに持たせて、そのオブジェクトを集合させてアプリケーションを作りましょうということ。オブジェクト指向にすることで期待できる恩恵は、コードの可読性が上がることだが、その恩恵はオブジェクトをどの程度扱えるかに左右されるところが大きい。そんなわけでオブジェクトの勉強は続く。
 今回はオブジェクトを学んでいると付いてくる概念の一つの要素であるプライベート変数を。

 先に結論をまとめておくと、JavaSriptでプライベート変数の機能を果たすものは作れるが、それをプロトタイプと組み合わせて使うことはできない。こんなふうに書けばプライベート変数をシミュレートできるとだけ知っておいて実際には使わず、変数への命名規則に準ずることで任意の変数をプライベート変数として扱いたいと示すのが妥当だと考えられる。もともとJavaScriptがプライベート変数を機能として提供していないのだから、プロトタイプという一つの機能を身代わりにしてまでプライベート変数にこだわる必要はない。
 ある変数をプライベート変数として扱いたければ、変数名の先頭にアンダースコア"_"をつけるのが慣例となっているようだ。参考書籍は『JavaScriptパターン―優れたアプリケーションのための作法―』。


 
 以前の記事でストップウォッチ機能をオブジェクト化した。
http://jsfiddle.net/hiroaki/w7Tbf/2/
var stopwatch = {};

stopwatch.time = null;

stopwatch.start = function()
{
stopwatch.time = Date.now();
};

stopwatch.getCurrentTime = function()
{
var diff = null;
if (stopwatch.time)
{
diff = (Date.now() - stopwatch.time) / 1000.0;
}
return diff;
};

stopwatch.stop = function()
{
stopwatch.time = null;
};

このストップウォッチオブジェクトは、"stopwatch.start()", "stopwatch.getCurrentTime()", "stopwatch.stop()"というそれぞれのメソッドを実行するだけで、オブジェクト実装の中身を知らなくてもストップウォッチの機能を果たしてくれる。中身としてはプロパティstopwatch.timeの値を参照したり、代入することでそれぞれのメソッドが機能を果たしている。
 このストップウォッチ機能はオブジェクトとして使えるものだが、オブジェクトとしての設計上、すこしあまい点がある。それはオブジェクトの外からプロパティstopwatch.timeが扱えるようになっている点である。プロパティstopwatch.timeの値が外から見られるし、stopwatch.timeを左辺におけば任意の値を代入できてしまう。C#などでは、任意の変数の参照や書き換えをオブジェクトの中でのみ可能にするプライベート変数というものがある。JavaScriptでは明示された仕様としてプライベート変数を備えているわけではないが、その機能をシミュレートして、プライベート変数として機能するものを作れる。上にあるコードを書きかえて、変数timeをプライベート変数にする。
デモ
function Stopwatch()
{
var time = null;

this.start = function()
{
time = Date.now();
};

this.getCurrentTime = function()
{
var diff = null;
if (time)
{
diff = (Date.now() - time) / 1000.0;
}
return diff;
};

this.stop = function()
{
time = null;
};
}

var stopwatch = new Stopwatch();

コンストラクタを使って書いてみた。timeをオブジェクトのプロパティでなく、コンストラクタ内の変数とした。そして各メソッド内で変数timeが使われているが、これはメソッド定義の真上の関数スコープで宣言されているtimeを参照することで解決される。オブジェクトの内部はそんなふうになっていて、このオブジェクトを外から見ると変数timeを参照する手段はなく、ただstart, getCurrentTime, stopのメソッドがあるだけだ。変数timeの値は外から見えないが、ストップウォッチとして不可分なく使えるメソッドが揃っているので、余計なものが外から見えなくなったぶんむしろこれでいい。オブジェクトの内部で値を保持していて、プロパティとしてオブジェクトの外に公開されていない変数。これをプライベート変数と呼ぶ。

 JavaScriptでプライベート変数を使うには問題がある。プロトタイプとプライベート変数が同時に使えないからだ。
function Stopwatch()
{
var time = null;
}

this.prototype.start = function()
{
??? = Date.now();
};

this.prototype.getCurrentTime = function()
{
var diff = null;
if (???)
{
diff = (Date.now() - ???) / 1000.0;
}
return diff;
};

this.prototype.stop = function()
{
??? = null;
};

var stopwatch = new Stopwatch();


 オブジェクトのメソッドをプロトタイプに移したとき、メソッドがStopwatchコンストラクタの外に出るので、変数timeにアクセスできない。これがJavaScriptでプライベート変数を使おうとしたときの弱点。プロトタイプとの併用ができない。プライベート変数が仕様にあるわけではないので、ここはプロトタイプを優先するのが吉か。
 命名規則に準じて以下のように書くのがおそらくベター。"time"を"_time"へと書き換え。
function Stopwatch()
{
this._time = null;
}

this.prototype.start = function()
{
this._time = Date.now();
};

this.prototype.getCurrentTime = function()
{
var diff = null;
if (this._time)
{
diff = (Date.now() - this._time) / 1000.0;
}
return diff;
};

this.prototype.stop = function()
{
this._time = null;
};

var stopwatch = new Stopwatch();
            

コメントの投稿

非公開コメント

プロフィール

hMatoba

Author:hMatoba
Github

最新記事
リンク
作ったものなど
月別アーカイブ
カテゴリ
タグリスト

検索フォーム
Amazon
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。