若手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に追加されるのではなくて、

  1. this._superをローカル変数に退避
  2. this._superにsuper classのprototypeの同名を代入
  3. 定義時に渡されたmethodを呼び出し
  4. this._superを元に戻す

という処理のラッパーmethodをclassのprototypeに追加されるようにしている。


this._superという同じ名前のmethodなのに、
呼び出し側のmethod毎に違うmethodが呼ばれるのはこういうわけ。


さらに、効率化のために、super classにoverrideされるmethodがない場合、
sub classで定義されたmethodの中でthis._super methodを呼んでいない場合は、
ラッパーmethod作成処理をスキップしている。


短いコードだけどかなり興味深いので、じっくり読んでみるといい。