こんにちは、
JavaScriptにおける継承
まず、
dir(document.createElement('span'))
実行結果は次の通りです。
![図1 Chromeでの実行結果#1 図1 Chromeでの実行結果#1](/assets/images/dev/serial/01/crossbrowser-javascript/0015/thumb/TH400_001.png)
こちらの通り、
![図2 Chromeでの実行結果#2 図2 Chromeでの実行結果#2](/assets/images/dev/serial/01/crossbrowser-javascript/0015/thumb/TH400_002.png)
さらに、
var span = document.createElement('span');
span instanceof HTMLElement;// true
span.__proto__ === HTMLElement.prototype;// true
という関係になっています。さらにHTMLElementの__
![図3 span要素の継承関係 図3 span要素の継承関係](/assets/images/dev/serial/01/crossbrowser-javascript/0015/thumb/TH800_003.png)
ところで、
JavaScriptにおける継承
さて、
function A(){
}
A.prototype.a = function(){
return 'a';
};
var a = new A();
console.log(a.a()); // a
function B(){
}
B.prototype.b = function(){
return 'b';
};
var b = new B();
console.log(b.b()); // b
この例ではAとBは互いに独立しています。どのようにすればAとBを結びつけることができるのか、
![図4 AとBの継承関係 図4 AとBの継承関係](/assets/images/dev/serial/01/crossbrowser-javascript/0015/thumb/TH800_004.png)
コンストラクタとインスタンスと関係として
a.__proto__ === A.prototype
が成り立つことは何度か取り上げてきましたが、
a.__proto__.__proto__ === B.prototype
という点です。すなわち、
A.prototype.__proto__ === B.prototype
ということです。ここで、
b.__proto__ === B.prototype
であることも加えると、
A.prototype.__proto__ === b.__proto__
という関係が導き出せます。
つまり、
function A(){
}
function B(){
}
B.prototype.b = function(){
return 'b';
};
A.prototype = new B();
// A.prototype.__proto__ === B.prototypeとなる
A.prototype.a = function(){
return 'a';
};
var a = new A();
console.log(a);
console.log(a instanceof B);// true
console.log(a.__proto__.__proto__ === B.prototype);// true
![図5 AとBの継承関係#2 図5 AとBの継承関係#2](/assets/images/dev/serial/01/crossbrowser-javascript/0015/thumb/TH800_005.png)
目的の通り、
function A(){
}
function B(){
}
B.prototype.b = function(){
return 'b';
};
A.prototype = new B();
A.prototype.constructor = A; // ※追加
A.prototype.a = function(){
return 'a';
};
var a = new A();
console.log(a);
![図6 AとBの継承関係#3 図6 AとBの継承関係#3](/assets/images/dev/serial/01/crossbrowser-javascript/0015/thumb/TH400_006.png)
これで目標としていた継承を実現することができました。
継承時の注意点
今回紹介した方法には注意すべき点があります。それはコンストラクタ内の処理です。今回のサンプルではコンストラクタAもBも何もしない関数として定義しているので、
function A(){
alert('A');
}
function B(){
alert('B');
}
B.prototype.b = function(){
return 'b';
};
A.prototype = new B(); // ここでもalert
A.prototype.constructor = A;
A.prototype.a = function(){
return 'a';
};
var a = new A();
console.log(a);
この例では、
そこで、
function A(){
alert('A');
}
function B(){
alert('B');
}
B.prototype.b = function(){
return 'b';
};
var dummy = function(){
};
dummy.prototype = B.prototype;
A.prototype = new dummy();
A.prototype.constructor = A;
A.prototype.a = function(){
return 'a';
};
var a = new A();
console.log(a);
console.log(a instanceof B);// true
一見すると、
まとめ
今回はプロトタイプベースの継承の具体的な方法を学びました。少々理解し難いところがあるかもしれませんが、