JavaScriptのprototype継承について再考してみるのメモ
2010/08/19(木) 11:00 Javascriptこのエントリーをはてなブックマークに追加

を読んでのメモ。
function SuperClass(one, two, three) {
    this.dataSet = [one, two, three];
}
SuperClass.prototype = {
    pop: function() {
        return this.dataSet.pop();
    }
};

function ChildClass() {
    this.state = "childy";
}
ChildClass.prototype = new SuperClass(10, 23, 45);
p(ChildClass);// ChildClassにはdataSetないよ
var c1 = new ChildClass(100, 13, 15);// この場合、引数は意味なし
p("c1 " + c1.dataSet);// c1にはないので、実際はc1.__proto__.dataSet
var c2 = new ChildClass(200, 30, 50);// 引数は意味なし
p("c2 " + c2.dataSet);// c2にもないので、実際はc2.__proto__.dataSet
p(c1 === c2);// false
p(c1.__proto__ === c2.__proto__); // true - c1とc2のprototypeを辿ると同じもの
a.dataSet[0] = 1000;
alert(b.dataSet.toString()); // 1000, 23, 45
最後のところで分かるように、c1とc2は違うものだけど、c1とc2のprototypeを辿ると同じものを示しているので、c1.dataSet (実際に参照されるのはc1.__proto__.dataSet) の値を変えると、同じものを参照しているc2.dataSetの値も変わってしまうって話。

何とかする方法としてChildClassのコンストラクタで、SuperClassのコンストラクタを呼べばいい。
function ChildClass() {
    SuperClass.apply(this, arguments);
    this.state = "childy";
}
ChildClass.prototype = new SuperClass;
ChildClassを上のに書き換えてから同じ事をしてみると
function SuperClass(one, two, three) {
    this.dataSet = [one, two, three];
}
SuperClass.prototype = {
    pop: function() {
        return this.dataSet.pop();
    }
};

function ChildClass() {
    SuperClass.apply(this, arguments);
    this.state = "childy";
}

ChildClass.prototype = new SuperClass(10, 23, 45);
var c1 = new ChildClass(100, 13, 15);// 引数を使ってSuperClassのコンストラクタを呼ぶ
// このときのthisはc1(結果的な意味で)なので、c1.dataSetができる
p("c1 " + c1.dataSet + "と" + c1.__proto__.dataSet);// それぞれ違う値
var c2 = new ChildClass(200, 30, 50);// c2.dataSetを作る
p("c2 " + c2.dataSet + "と" + c2.__proto__.dataSet);
p(c1.__proto__.dataSet === c2.__proto__.dataSet);// true だけど
p(c1.dataSet +"と"+ c2.dataSet);// c1とc2はそれぞれコンストラクタで作ったdataSetを持つ
という感じでc1.dataSetの値を書き換えても、c2.dataSetの値は変わらなくなった。

というお話だったけど、継承とか殆ど書かないのでnewしたものをさらにnewした記憶がなかった…

名前:  非公開コメント   

  • TB-URL  http://efcl.info/adiary/062/tb/