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でチョロッと書くぐらいなら情報隠蔽しなくてもいいし、
ほとんど使う機会とか無いだろうな。


出来ることは分かったが、使わねーよ!