プロトタイププロパティ

JavaScriptで関数を生成すると自動で、prototypeプロパティが生成されます。

function MyClass(x) {
  this.x = x;
}
var foo = new MyClass(10);
console.log(foo);
関数(オブジェクト)をコンソールで確認

このprototypeプロパティにメソッドを追加することで、生成したインスタンスからメソッドをコールすることができるようになります。

function MyClass(x) {
  this.x = x;
}
MyClass.prototype.show = function() {
  return this.x;
};
var foo = new MyClass(10);
console.log(foo);
protorypeにメソッド追加

new演算子の暗黙のルール

prototypeプロパティを使用せずに、下記のように定義することもできます。

function MyClass(x) {
  this.x = x;
  this.show = function() {
    return this.x;
  };
}
var foo = new MyClass(10);
console.log(foo);

しかし、これをコンソールで確認してみるとshowメソッドがインスタンスに生成されています。

prototypeを使用しない例

これはnew演算子の暗黙のルールで、関数の生成と共に var this = {};が定義されて、それを return this;していることにあります。

function MyClass(x) {
  // var this = {};
  this.x = x;
  this.show = function() {
    return this.x;
  };
  // return this;
}
var foo = new MyClass(10);
console.log(foo);

2行目と7行目のコメントアウトしている箇所が暗黙のルールになります。無駄な関数(オブジェクト)の生成をしないという点でもprototypeプロパティを使用しての定義が良いようです。

プロトタイプチェーン

new演算子で一度インスタンス化したオブジェクトにしたあとに、クラス自体にメソッドやプロパティを追加するとインスタンスは、それを参照することができます。読み込みと書き込みで継承動作が異なります。違いを以下のコードで確認します。まずは、読み込み編。

function MyClass(x) {
  this.x = x;
}
var foo = new MyClass(10);
console.log(foo.x);          // 10
console.log(foo.y);          // undefined

MyClass.prototype.y = 5;

console.log(foo.y);          // 5

8行目でyというプロパティを追加しました。その後、インスタンスfooyを参照できることが確認できました。続いて、下記のコードは、prototypeに実装したプロパティの値を上書きして、別のインスタンスからその値を参照した場合の例。

function MyClass(x) {
  this.x = x;
}
MyClass.prototype.y = 5;
var foo = new MyClass(10);
foo.y = 555;
console.log(foo.y);  // 555

var bar = new MyClass(10);
console.log(bar.y);  // 5

prototypeで定義したプロパティの値を書き換えたにも関わらず、インスタンスbaryの値は元のままです。書き込み時にはプロトタイプチェーンをたどらないことがわかります。インスタンスが直接のプロパティをみているということになります。

インスタンスからプロパティを削除してみるとわかります。

function MyClass(x) {
  this.x = x;
}
MyClass.prototype.y = 5;
var foo = new MyClass(10);
foo.y = 555;
console.log(foo.y);  // 555

var bar = new MyClass(10);
console.log(bar.y);  // 5

delete foo.y;
console.log(foo.y);  // 5

12行目でインスタンスfooからyプロパティをdeleteした後に、yを参照してみると「5」という値が出力されました。これは親(prototype)のyを参照しているということになります。なるほど、スッキリ。