若手IT勉強会 secrets of the JavaScript Ninja 読書会(第5章 prototypeの話)
注意
基本的に自分が気になったことしか此処には書かないので、
これだけ読んでもNinja本読んだ代わりには全くならないですよ、っと。
HTML Prototypes
HTMLElement.prototypeに生やしたmethodが、
document.getElementById等で取得したDOM要素のobjectで使える。
多分、document.createElementで作ったDOM要素もそうだと思う。
var elem = new HTMLElement();
みたいなことはできない。
IE8以降とモダンブラウザで使えるらしい。
ネイティブオブジェクトの拡張
便利だけど、Objectの拡張は気をつけて行うべき、
Numberの拡張はやめたほうがいい。
なんでNumberの拡張をやめておいたほうがいいかというと、
Numberはprimitiveのnumberのラッパーなんだけど、
- numberを裸のリテラルで書くとprimitiveとしてしか扱われない
- リテラル表記を()で括るとラッパーオブジェクトとしても扱われる
- numberを代入した変数は、ラッパーオブジェクトとしても扱われる
というように、prototypeに追加して生やしたmethodを使えるかどうかが
分かりにくいからとかそういう話。
prototypeを使って継承可能なclassを定義する話
基本的にJohn Resig - Simple JavaScript Inheritanceの話
sub classでoverrideしたmethodの中からthis._super methodとして、
super classの同名methodを呼ぶことが出来る。
これを実現するからくりが面白い。
var Person = Class.extend({ init: function(isDancing){ this.dancing = isDancing; }, dance: function(){ return this.dancing; } }); var Ninja = Person.extend({ init: function(){ this._super( false ); }, dance: function(){ // Call the inherited version of dance() return this._super(); }, swingSword: function(){ return true; } });
こんな感じでclassの定義を行っている(本の方だとextendでなくsubClassだった)。
この時、extendに渡されたobjectが持っているmethodが、
そのままそのclassのprototypeに追加されるのではなくて、
- this._superをローカル変数に退避
- this._superにsuper classのprototypeの同名を代入
- 定義時に渡されたmethodを呼び出し
- this._superを元に戻す
という処理のラッパーmethodをclassのprototypeに追加されるようにしている。
this._superという同じ名前のmethodなのに、
呼び出し側のmethod毎に違うmethodが呼ばれるのはこういうわけ。
さらに、効率化のために、super classにoverrideされるmethodがない場合、
sub classで定義されたmethodの中でthis._super methodを呼んでいない場合は、
ラッパーmethod作成処理をスキップしている。
短いコードだけどかなり興味深いので、じっくり読んでみるといい。