チュートリアル-6 : __proto__ [Edit]

全てのオブジェクト、つまりobject, Function object, MovieClip objectは"__proto__"という名のビルトインプロパティを持っています。そしてその__proto__はそれ自体がそのオブジェクトのコンストラクタのprototypeの値(object値)への参照になっています。

例18
MyClass = function () { }
myObj1 = new MyClass();
trace(MyClass.prototype == myObj1.__proto__); //出力:true

例18では、1行目の時点で、MyClassというFunction objectにprototypeプロパティが自動的に設定されます。そしてその値はobject値です。
次に2行目の時点で、myObj1というobjectに__proto__という名前のプロパティが自動的に設定され、その__proto__はmyObj1のコンストラクタであるMyClassのprototypeプロパティの値を参照します。
つまり、MyClass.prototypeとmyObj1.__proto__は同一のobject値を値として持つということです。そしてMyClass.prototypeに何らかのユーザ定義プロパティが定義されれば、それは、myObj1.__proto__からも参照できます。

例19
//Personクラスコンストラクタを定義
Person = function (name) {
  this.name = name;
};

//PersonクラスコンストラクタのprototypeプロパティにgetNameメソッドを定義
Person.prototype.getName = function() {
  trace("getName called");
  return this.name;
};

//インスタンスperson1を生成
person1 = new Person("foo");

trace(person1.getName()); //トレース1
/*出力:
getName called
foo
*/

trace(person1.__proto__.getName()); //トレース2
/*出力:
getName called
undefined
*/

例19では、トレース1でPerson.prototypeに定義されたgetNameメソッドが呼ばれ、this.name、すなわち'foo'が返されます。トレース2でも、出力結果が示すように、getNameメソッドは呼ばれますが、person1.__proto__自体はnameプロパティを持っていないので、this.nameはundefinedになります。

トレース2の結果からわかるように、getNameメソッドは、Person.prototypeと同じ値を持つperson1.__proto__のプロパティであると言って良いのですが、トレース1で行われているように、person1から直接呼ぶことができます。つまり、person1.getNameと書くと、person1というobject自体のgetNameプロパティをまず探し、そこにgetNameが無い場合、自動的にperson1.__proto__の中を探す、という仕組みになっています。そしてperson1.getName()と書かれた場合、person1.__proto__.getNameが呼ばれますが、getName実行時のスコープはperson1.__proto__ではなく、person1自身になります。つまり、getNameというfunctionのボディ内の'this'はperson1を参照します。

prototypeと__proto__は以上のような合理的な仕組みになっています。

~つづく~

その他の記事