JavaScriptでデータの情報隠蔽
よく考えたらJavaScriptでもデータの情報隠蔽出来るな。普通はこんなことやらないけど。
今回はimmutableな二次元ベクトルを作りながら説明しよう。
とりあえず普通に作る。
function createVector2D(x_,y_) { return { x:x_, y:y_, length:function(){ return Math.sqrt(this.x*this.x+this.y*this.y); } } } var v = createVector2D(1,0); v.x; // 1 v.length() // 1.41421... v.x = 3; //代入で値の変更が出来てしまう...。
x,y,length()というメンバを持つオブジェクトを返すcreateVector2D()という関数を定義した。
このまま生成したオブジェクトを使っても、もちろん、x、yなどのプロパティの変更が出来る。
それを変更不可能にしたい、っていうのが今回の話題。
メンバ名を引数に取り、値を返す関数を作る。
オブジェクトをそのままreturnしてしまうと、メンバのアクセスを制限することが出来ない。
ならば、オブジェクトにアクセスする関数を作り、その関数を返せば、メンバに直接アクセスできなくなる。
関数によるオブジェクトのカプセル化。
function createVector2D(_x,_y) { var o = { x:_x, y:_y, length:function(){ return Math.sqrt(o.x*o.x+o.y*o.y); } } return function(memberName){ return o[memberName]; } } var v = createVector2D(1,0); v("x") // 1 v("length")(); //1.4142... v("x") = 3; //もちろん出来ない。
メンバのアクセスの仕方が少し特殊になる。
これで、xやyなどの値を外から変更できなくなった。
読み取り専用のオブジェクトに変換する関数を作る
一つのオブジェクトにつき、ファクトリメソッドを一つ作らないといけないのはメンドクサイ。
ならば、普通のオブジェクトから、読み取り専用に変換する関数を作ればいい。
function toReadOnly(o) { return function(memberName){ var member = o[memberName]; if(member instanceof Function) { return function(){ return member.apply(o,arguments); } } else{ return member; } } } function createVector2D(x_,y_) { return { x:x_, y:y_, length:function(){ return Math.sqrt(this.x*this.x+this.y*this.y); } } } var v =toReadOnly(createVector2D(1,0)); v("x");//1 v("length")(); //1.4142... v("x") = 3; //もちろん出来ない。
createVector2D()は最初のコードと同じ、オブジェクトを生成する関数。
toReadOnly()というのが、読み取り専用にする関数。
toReadOnly()の引数にオブジェクトを入れれば、2番目のコードのような読み取り専用のオブジェクトが生成される。
ただし、アクセスの仕方が、同様に特殊なので注意。
これなら、新しく作ったオブジェクトに対しても、簡単に読み取り専用に出来る。
var o = toReadOnly({name:"tako",age:20}); o("name"); //"tako" o("age"); //20 o("age") = 21; //もちろん出来ない。
作ってみた感想
JavaScriptの使い方が分からん。エラーを出せ!
クロージャ使えば、何でも出来て便利だね!
でもアクセスの仕方が仕方がキモいし、JSでチョロッと書くぐらいなら情報隠蔽しなくてもいいし、
ほとんど使う機会とか無いだろうな。
出来ることは分かったが、使わねーよ!