JavaScriptのプロトタイプ継承を理解する

継承

継承とは、あるオブジェクトが別のオブジェクトを基にすることができるプロセスです。

私は Hero プロトタイプを作成し、それを使用して superman という名前の新しいオブジェクトを作成しました。 しかし、このオブジェクトでは何もしていません。 そこで、dialogue.

function dialogue() {
console.log('I am ' + this.name);
}

という別の関数を作成することで対処しましょう。しかし、今コードを実行すると、この関数は名前が本当は何であるかを知らないので、何も起こりません。 そのためには、

この新しい関数に Hero のプロパティと同じものを持たせる必要があります。 この関数内に書き留める代わりに、JavaScript に Hero プロトタイプからそれらを継承するように指示すればよいのです。

dialogueHero.prototype 上に置くことにより、Hero のすべてのインスタンスがそれを使用できるようにしています。

Differential Inheritance

JavaScript には「差分継承」という別の継承モデルも用意されています。 このモデルでは、メソッドが親から子へコピーされることはない。

ここで、superman は実際には dialogue() という独自のメソッドを持っていません。

JavaScriptエンジンはコード内でsuperman.dialogue()を見つけると、supermanオブジェクトの中にあるdialogueというプロパティを探します。 それが見つからない場合、プロトタイプチェーンで superman の親 Hero.prototype を探します。 そこで Hero.prototype.dialogue を見つけ、superman にバインドされた this で呼び出します。

Object.create()

Superman の新しいクラスを作成し、Hero プロトタイプの属性を継承させれば、さらに排他的にすることが可能です。 これは、Superman のプロトタイプを Hero のプロトタイプに次のように代入することで可能です:

function Superman() {}
Superman.prototype = Hero.prototype

しかしこれは、SupermanHero を両方とも同等にしているに過ぎません。 本当に必要なのは、Hero プロトタイプをベースにした新しいオブジェクトである。 ES5以降、JavaScriptにはObject.create()という組み込み関数が用意されている。

Superman.prototype = Object.create(Hero.prototype);

これは、Hero プロトタイプに基づく新しい空のオブジェクトを作成し、それを Superman プロトタイプに割り当てます。 つまり、Heroプロトタイプにあるすべてのプロパティは、Supermanプロトタイプからアクセスできるようになります。 new Hero を呼び出す代わりに new Superman を呼び出しても、すべてが正常に動作します。

しかし、出力をよく見てみると、その中に undefined があることに気づきます。 それは、現在 Hero が自分自身のためだけのコンストラクタであるためです。 Hero のプロパティを Superman プロトタイプの内部で call しなければなりません。

function Superman() {
Hero.call(this, 'Superman', 'Clark Kent', 'Krypton')
}

以下のように、MarvelMovies という別のコンストラクタを作ってみましょう。

function MarvelMovies(movieName, releaseYear) {
this.movieName = movieName;
this.releaseYear = releaseYear;
}

関数がコンストラクタとして使われるとき this は新しく作るオブジェクトを指しています。 このコンストラクタでは、movieNamereleaseYear を引数として取り、それらの値を avengers という新しい MarvelMovies インスタンスの movieNamereleaseYear プロパティに代入しているわけです。

var avengers = new MarvelMovies("avengers", 2012);

次に、このプロトタイプに対して、次のように output という新しいメソッドを作成します。

MarvelMovies.prototype.output = function() {
return "Movie: " + this.movieName + " Released in " + this.releaseYear;
}
console.log(avengers.output());

将来の継承

継承の本当にすばらしい側面は、JavaScript によって、クラスを定義した後でもその機能を修正または拡張できるということです。

これを説明するために、次のような配列を作成します:

var numbers = ;
Array.prototype.shuffle = function() {
return this.sort(function() {
return Math.round( Math.random() * 2) - 1;
});
};
console.log(numbers.shuffle());

ここで、numbers 配列は Array.prototype.shuffle が存在する前に存在しています。 しかし、JavaScriptでは、プロパティの参照はプロトタイプの連鎖を上へ上へと進みます。 これは、配列が新しいメソッド shuffle へのアクセスをまだ持っている理由です。なぜなら、実際に使用しようとしているときに Array.prototype 上に存在するからです。

簡単に言うと、配列を作成し、それから戻ってすべての配列に新しいメソッドへのアクセスを提供しました。

コメントを残す

メールアドレスが公開されることはありません。