Jintrick.netagenda2003年11月アーカイブ → 2003年11月26日

ObjectリテラルやisSubClassOfについて

EcmaScriptの仕様書によると、Objectリテラルのプロパティ名にはStringリテラル、Numericリテラルが許されます。その他isSubClassOfメソッドの作成など。

Objectリテラルの構文

var obj = new Object;
obj.prop = "value"

上記はObjectリテラルを利用して次のように書けます。

var obj = {prop: "value"};

では、Property名がIdentifierで表記できない、次のような場合はどうでしょうか。

var obj = new Object;
obj["prop name"] = "value";

これも、実はObjectリテラルで次のように書けます。

var obj = {"prop name": "value"};

期待が膨らんできたのでEcmaScriptの仕様書を読んでみました。

ObjectLiteral:
	{ }
	{ PropertyNameAndValueList }

PropertyNameAndValueList:
	PropertyName : AssignmentExpression
	PropertyNameAndValueList , PropertyName : AssignmentExpression

PropertyName:
	Identifier
	StringLiteral
	NumericLiteral

ECMAScript Language Specification 3rd edition (PDF) より

というわけで、残念ながら:

var obj = {function(){return "prop name";}(): "value"}

これは構文エラーでした。PropertyNameにおいて、Identifier以外に許されるのはStringリテラルと Numericリテラルだけであって、式が評価されることは全くないようですので、変なトリックを考えるのを諦めました。

isSubClassOfを定義する

EcmaScript(JavaScript)において、あるインスタンス c のコンストラクタ C は、c.constructorで参照することができますが、そのコンストラクタ関数が外部のスクリプトファイルに定義されていると、何故かこれがObjectのコンストラクタになってしまいます(理由を追求する気力はありません)。

これを何とかするには、コンストラクタ関数内で、毎度this.constructorプロパティに自分自身を代入すると良いようです。

function C(){
	this.constructor = C;
}

というのは嘘で、prototypeを使って全インスタンスで共有してしまった方が良い場合が多い筈です。

C.prototype.constructor = C;

これで、インスタンス c が コンストラクタ C によって生成されたものであるかどうかは、c.constructor === Cでその真偽値を得ることができます。

ところが、例えばコンストラクタ C のprototypeを受け継いだ、D というコンストラクタがあったとします。

Function.prototype.inherit = function(superClass) {
	/* See: http://www.skipup.com/~peace/javascript/ */
	function Temp() {}
	Temp.prototype = superClass.prototype;
	return this.prototype = new Temp; };

function C(){}
C.prototype.constructor = C;
function D(){}
D.inherit(C);
D.prototype.constructor = D;

この D が、C を継承しているかどうかを判断するにはどうすれば良いでしょうか。また、同様に D を継承した E が、C のprototypeを受け継いでいることはどうやって調べればよいでしょうか。

そのような方法は見つからなかったので、isSubClassOfというメソッドを作ってみました。

instanceof 演算子が見つかったので以下はあまり意味はありません。

まず、スーパークラスをコンストラクタから参照できるようにするために、上記のinheritメソッドに一行加えました。

Function.prototype.inherit = function(superClass) {
	function Temp() {}
this.Super = superClass;
	Temp.prototype = superClass.prototype;
	return this.prototype = new Temp; };

コンストラクタ関数といっても、ただの関数と同様にFunctionクラスのインスタンスです。上記のinheritメソッド同様、FunctionのprototypeにisSubClassOfメソッドを追加してやることで、これを全コンストラクタ関数で共有させます。

Function.prototype.isSubClassOf = function(superClass, /*IGNORE THIS*/self) {
	if (self === void 0)
		self = this;
	if (self === superClass)
		return true;
	else if (self.Super !== void 0)
		return arguments.callee(superClass, self.Super);
	else
		return false;
};

先ほどの D のインスタンスを d とすれば、d.constructor.isSubClassOf(C)で、C のprototypeを継承しているかどうかその真偽値が分かるという寸法です。因みにd.constructor.isSubClassOf(D)でもtrueですが、意味論的に少し変かもしれません。


webmaster@jintrick.net
公開: 2003年11月26日
カテゴリ: Javascript