日記帳

日記です。

private なプロパティ

ECMAScript 3rd Edition では private なプロパティを実現するために以下のようなコードが書けます。

function Value()
{
	var value = 0;
	this.getValue = function() { return value; }
	this.setValue = function(newValue) { value = newValue; }
}

var obj = new Value();
alert(obj.getValue());
obj.setValue(5);
alert(obj.getValue());

valueValue() のローカル変数なので外部から変更することはできません.
これで setter 経由でアクセスするしかなくなるので以下のように設定しようとする入力値を確実にチェックすることも可能になります。

function ValueWithRange(min, max)
{
	var value = min;
	this.getValue = function()
	{
		return value;
	}
	this.setValue = function(newValue)
	{
		if(newValue < min)
			value = min
		else if(max < newValue)
			value = max
		else
			value = newValue
	}
}

var obj = new ValueWithRange(0, 10);
alert(obj.getValue());
obj.setValue(5);
alert(obj.getValue()); // => 5
obj.setValue(-20);
alert(obj.getValue()); // => 0
obj.setValue(20);
alert(obj.getValue()); // => 10

素晴しい!これはいいものだ!これで直接プロパティを書き換えられる心配がない!
getValue() はつねに min 以上 max 以下を返すことを保証できるのだ!
アクセサメソッドはみんなこの方式にしよう!

…と見せかけてそうでもないって話です.

  1. 定義された getValue()、 setValue() は正しく継承されない
  2. プロパティは書き換えられないけどメソッドはいくらでも書き換え可能

1. は以下の通りで parent を継承した child の value を変更したつもりが parent の value も書き換わってしまうってことです.

var parent = new ValueWithRange(0, 10)
parent.setValue(5)
var child = parent.clone()
child.setValue(8)           // child を変更したつもりが
alert(child.getValue());    // => 8
alert(parent.getValue());   // => 8 parent も変更されている    

これでは普通のアクセサメソッドとしては使えません(でもこれはこれで別の用途に使えそうな気がしますけど).

2. は,当り前のことですが以下のようにすれば getValue() が指定した範囲外を返されるってこと.

child.getValue = function() { return -100; }

つまり変数を変更できなかったとしてもアクセサが返す値については何も保証できていないということ.

これは実行時にメソッドを書き換えることができる言語はほとんどに言えそうだけど完全に private なプロパティを実現することは不可能な気がする.これはつまり完全に Immutable なオブジェクトを実現できないってことでもあります.

もちろん言語仕様的に private であることを保証できなかったとしてもプログラマが上のようなコードを書かなければ済む話なので実用上問題になりません.しかしそれならば普通にプロパティを書き換えるアクセサメソッドでも同じことが言えてしまいます.

とりあえずの結論.ECMAScript3 でクロージャを利用して作った private なプロパティは,

  • 継承できないのでは普通のアクセサメソッドとしては使えない
  • 完全な private は実現できていない

ということで attr() *1 では採用しませんでした.そんだけ.