◆ Object.create 使ってた
◆ util.inherits でお手軽継承

前回:自分が使う継承方法をまとめました
JavaScriptで継承する

今回:そういえば Node.js には継承用ユーティリティがあったようなと思って 調べてみます




0.8から0.10への移行に書かれたものなので もう5.0が出たNodejs的には古いものですが JavaScript の仕組みなので特に変わってないでしょう ということでコレ使います
https://github.com/nodejs/node/wiki/API-changes-between-v0.8-and-v0.10
// Broken-Style Inheritance, which has never been safe or wise
// but is shown on many broken tutorials around the web.
function Child() {}
Child.prototype = new Parent(); // <-- NEVER EVER DO THIS!!
// If you see anyone doing this in any javascript library ever,
// post a bug telling them that it is a huge terrible mistake!
// Inheriting from a class should not call that class's ctor
// on the prototype shared with EVERY instance of the child class!

// Correct-Style Inheritance
function Child() {
Parent.call(this);
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
});
// "Gee that's a lot of lines! I wish there was a helper method!"
// There is. Do this:
util.inherits(Child, Parent);

英語でよくわからないですが とりあえず
function Child() {}
Child.prototype = new Parent();
これはダメ

function Child() {
Parent.call(this);
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
});
こっちが正しい

util.inherits(Child, Parent);
こうやって短く書ける

ということですね

この方法では Child.prototype を置き換えてしまっています
それでも ちゃんと constructor を設定してるので 問題はないです
(Node.js で使われてるわけですし 間違ってたら困りますけど)

でも Parent.prototype に置き換えるわけじゃないです
Object.create なので 新規のオブジェクトを作って そのオブジェクトの __proto__Parent.prototype が設定されてます
__proto__ と書かずにやりたいからこうしてるようです

だいたいこういうことしてます
Child.prototype = {constructor: Child, __proto__: Parent.prototype}
プロトタイプチェーンはこうなっています
{Child と Parent のコンストラクタで設定されるインスタンス}

{新規オブジェクトで置き換えられたChildのprototype}

{Parentのprototype} ← {Parentのインスタンス}

{Object.prototype}

せっかくなので util.inherits のコードを見てみます
PCに入ってた古い版ですが 新しくなっても変えるところじゃなさそうなので v0.10.25 のです
function (ctor, superCtor){
ctor.super_ = superCtor;
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configrable: true
}
});
}

Child にあたる関数の super_ プロパティに親関数が入ってるんですね
こういうのがあったほうが便利なことがあるのかもしれません

これがあると インスタンスから 親となる関数を簡単にたどれます
var c = new Child
c.constructor.super_ // Parent
c.constructor.super_.super_.super_ // Parent of Parent of Parent

もしなかったら
c.__proto__.__proto__.constructor // Parent
c.__proto__.__proto__.__proto__.__proto__.constructor // Parent of Parent of Parent
さすがに これはちょっと……
めったに使うことはないと思いますけど ないよりはあったほうが良さそうです

ところで util.inherits はプロトタイプチェーンを繋いでくれるだけなので
Child 関数の中で Parent call するのは自分でやらないとダメです
どんな引数で call するのかわからないので ユーティリティ関数じゃできないですからね