closureの利用を考える

closure_memo_001
javascriptの高度なtopicといえば、closureだと思う。
理解が難しいと思う。カウンターを作ってみた時は感動したけど、なかなか理解が汎化していかない。それで、まとめを書いて見ることにした。
他にも、いろんなサイトを見て回った。
下のコードの例は、上の記事のものと全然違うものもあります。信頼性を求める人は上のリンクを辿って下さい。

setTimeoutでの関数の参照で使う

setTimeoutには、関数オブジェクトの参照か無名関数の定義式を入れる事になっている。setTimeout(ref_func_obj, seconds)

ただ、関数オブジェクトではなく、実行式を書きたい時は多い。fun()といった後ろに () が付く形。

そこで、引数をくるんで、引数なしの関数オブジェクトを返すようにする。org_funcが与えられていた時、引数を定義式の中に組み込んでしまう形のnew_funcを作り(参照させ)、それをsetTimeoutに使う。

Function.prototype.curry = function(arg){
  var self = this;
  return function(){
    self.apply(this, [arg]);
  };
};
var org_func = function(a){
  console.log(a);
};
new_func = org_func.curry("konitiwa");
function a(arg){
  setTimeout(new_func, 2000);
}

こんな感じかな?これをカリー化と言うのはまずいのだろうか?

Functionクラス(Functionオブジェクトのprototype)をOpen Class?するのは汚い方法かもしれないけど、しょうがない。

リンク先の記事では、オブジェクト、メソッド、メソッドへの代入式の3つをclosureして?新しい関数を作っている。

動的に作成したDomのイベントに関数を定義

動的にDomを作るconstructor関数を作ってやる。その時に、イベントでtriggerされる関数をつけてやりたい。でも、その関数の定義は外に出しときたい?(ここら辺、よく分かってない、、、)

オブジェクトとメソッド名を与えると、そのオブジェクト[メソッド名]という関数名(メソッド名)で、イベントと新規に作ったDomオブジェクトを引数に取る関数を作るようにする。

function associateObjWithEvent(obj, methodName){
  return function(e){
    e = e || window.event;
    return obj[methodName](e);
  };
}

これを、Domを作るconstructor関数に組み込む。thisのメソッドという形になる。

function DhtmlObject(elementType, id){
  var el = document.createElement(elementType);
  this.ele = el;
  el.id = id;
  el.innerHTML = "New Div";
  document.body.appendChild(el);
  if(el){
    el.onmouseover = associateObjWithEvent(this, "doMouseOver");
  }
}

そして、インスタンスメソッドとして、doMouseOverを定義すれば、この例だと、mouseoverでtriggerされるeventになる。

DhtmlObject.prototype.doMouseOver = function(event){
  console.log(event, this.ele);
};
//それで、動的にDomを作る(タグ、IDを指定)
new DhtmlObject("div", "divId");

これで、Domを作成する定義式と、イベントが起きた時に実行される関数を分離できた。作ったdomをglobal変数に入れて、ごにょごにょする必要もなくなった。(ここら辺りは、理解が怪しい)

ローカル変数の作成の重複を避ける

関数を呼び出すたびに、その関数のローカル変数を作るのはさけたい。よく例題に出るカウンターの例と同じタイプ。

closureにすれば、そのローカル変数(closureされる変数)は共通化される。

divの中にimgタグをいれる形のdocument.elementを作る。この時に、文字列をinnerHTMLに突っ込む形にする。それで、共通部分をローカル変数に、変わる部分はパラメータとする。

closureを使うべきでない場合

内部関数を作る事による速度低下に気をつける。closureを作ったけど、利用時に、その環境を使わないのなら、closure を作らず、外側で関数を定義しておいて、それをassignしてもよい。

constructor関数内で、this.method1 = function(){….}と定義して、closureを作るのは、呼び出し回数が少ない場合に限定する。そのconstructorが何回も使われるものであれば、AConstructor.prototype.method1 = function(){….}と、constuctor関数の外で、定義していく。

This entry was posted in その他 and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <img localsrc="" alt="">