tohokuaikiのチラシの裏

技術的ネタとか。

匿名関数でDOMを再帰的に駆け上がって調べる

自分の親のDOMを調べていって、「あるIDだったらそのDOMに対して処理を行いたい」っていう場合

ってありますよね。要するに、

ってな場合。ここで、DOMがもう変わらない!ってんだったら話は楽だけどそんなのは汎用性もなく後々に憂き目を見ることは確実なわけで。

方法その1 : とりあず、forでまわしてparentNodeをしらみつぶしに調べる

ってのはわりとすぐ思いつく。

for (var i=0, j=10; i<j ; i++){
    // ここでひたすらparentNodeを駆け上がっていく方法
    var dom = targetDom.parentNode;
    if (dom.id=="hogehoge"){
           return dom;
    } else {
           targetDom = targetDom.parentNode;
    }
}

こんなんをボタンのonclickにたいして結んでおく。

でもこれだと10階層しかさぐれない。マジックナンバーがでちゃってるんですね。

そうすると、DOMの階層が増えちゃった場合てきめんにアウト。


方法その2:Functionを外だしにして、再帰的な処理

ひとつ関数オブジェクトを作って、再帰処理をさせようって話。これで、階層に対するマジックナンバーは消える。

こんなかんじ。

reflexive = function(){};
reflexive.prototype = {
	loop: 0,
    targetID: null,
	initialize: function(sourceDOM, targetID){
        var self = this;
		this.targetID = targetID;
		sourceDOM['onclick'] = function(){
            var dom = self.searchBody(sourceDOM);
			if (dom){
                alert(dom.className);
            }
        }
    },
	searchBody: function(dom){
		if (this.loop>10){
			alert("too mach loop");
			return;
		}
		if (dom.id==this.targetID){
			return dom;
		} else {
			this.loop++;
			return this.searchBody(dom.parentNode);
		}
	}
};


var ref = new reflexive();
ref.initialize(document.getElementById('btn'), "hogehoge");

最後の行のinitializeで見つけたいDOMのIDとonclickしたいDOMを定義してやる。

これでもいいかなーって感じなんだけど、別プロパティにfunctionを定義するのがどうもいまいちっぽい。

JavaScriptぽく一つの匿名関数をぐるぐるっとまわしてやりたいなーって感じです。犬が自分のしっぽを追い回すようにな。その際、仲介者はいらんよなーって感じで。

方法その3 arguments.calleeを使う

で、この記事を参考にして、argument.calleeを使ってみた。
連載:Ajax時代のJavaScriptプログラミング再入門:第2回 JavaScriptの関数をマスターしよう (4/4) - @IT

reflexive = function(){};
reflexive.prototype = {
  targetID: null,
  btn: null,
  loop: 6,
  initialize: function(btn, targetID){
      var self = this;
      this.targetID =targetID;
      this.btn = btn;
      
      btn['onclick'] = function(){
          self.loop--;
          if (self.loop<1){
              return;
          }
          dom = self.btn;
          if (dom.id == self.targetID){
              alert(dom.className);
              return ;
          } else {
              self.btn = self.btn.parentNode;
              arguments.callee();
          }
      }
  }
};
var ref = new reflexive();
ref.initialize(document.getElementById('btn'), "hogehoge");

って感じ。

でも、なんか

this.flash.getKeys is not a function
http://d.hatena.ne.jp/js/local_storage.js
Line 92

ってエラーがでるんだよね。Jsがはてなのなんで、あまり気にしないんだけど。たぶん、ローカルのFlashにこの編集中の記事を保存する際のエラーなんだけど。うーん。ちょっと気になる。