せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【HELP済】【JavaScript 】bind関数を引数なしで呼ぶと。bindでクロージャー。

 
■topic summary
what means -> callback.bind() ???


 
この本を読んでるんだけど、すごいボリューム。

パーフェクトJavaScript (PERFECT SERIES 4)

パーフェクトJavaScript (PERFECT SERIES 4)

頭わいてる!

 

引数なしのbind呼び出し?

21章にこんなサンプルコードが。

event_source.on('foo', callback.bind());
event_source.removeListener('foo', callback.bind());

 

本には、

これらのコードは、イベントハンドらを意図通り削除できていません。なぜなら2つのbindの呼び出しはそれぞれ別の関数オブジェクトの参照を返すからです

とある。

なんでbindメソッドを引数なしで呼んでいるの??
 
うーん、、

The value is ignored if the bound function is constructed using the new operator.

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

Mozilla仕様にはこう書いてあるけど、
EventEmitter.onメソッドの引数でbindメソッドが実行されると
newを使ってるのと同等とみなされているのかな。。?
よく分からないな。

引数の省略はできないとIEには書いてあるし。。
bind メソッド (Function) (JavaScript)


まだ自分はthisの概念が分かってないのかもしれない。
とりあえずメモしておこう。。。



 

追記

 
ピタゴラさんからコメントをもらったよ!
f:id:sekaiya:20131116082630j:plain

なるほど。
bindが別々の関数オブジェクト(クロージャ)を返すことを表現したかったのか!
別にNode.jsは関係のない話なんだね。

なら手元で実際に動かして試してみよう。
ありがとうピタゴラさん。。!

 

bind関数、引数あり

fn=function(){
console.log(this);
}
var a={x:"aaa"};
fn.bind(a)();

 
■実行結果

Object {x: "aaa"}

 
fnメソッドのレシーバーはaオブジェクト。



 

bind関数、引数なし(ケースA)

fn=function(){
console.log(this);
}
var a;
fn.bind()();

 
■実行結果

Window {top: Window, window: Window, location: Location, Proxy: Object, external: Object…}

 
なるほど。
エラーになるわけではないのか。
ただ、thisがWindowオブジェクト参照になるのは
クライアントサイドJavaScriptでのグローバルオブジェクトが
Windowオブジェクト だからであって、
ここに依存したコーディングは避けたほうがよさそう。

 

bind関数、引数がundifined(ケースB)

fn=function(){
console.log(this);
}
var a;
fn.bind(a)();

 
■実行結果

Window {top: Window, window: Window, location: Location, Proxy: Object, external: Object…}

 
引数なしと同じ結果。

 

参考

上記のケースA ケースB について、
通りすがりさんから、コメントをもらったよ。
f:id:sekaiya:20140101212654p:plain
 
ふむふむ。通りすがりさんありがとう!
なるほど。
thisがwindowオブジェクトになった場合は
引数でレシーバの指定が出来てない可能性があるかもしれない、と頭に入れておこう。
 

別の関数オブジェクトの参照を返す?

 
以上を踏まえて、本に書いてあった

2つのbindの呼び出しはそれぞれ別の関数オブジェクトの参照を返す

について、実際に確かめてみよう。

 

素朴なクロージャー

まずは素朴なパターン

countup = function(){
  var cnt = 0;
  return function(){console.log(++cnt);}
}
var fn = countup();
fn();
fn();

 
■実行結果

1
2


  

あえてのbind

bindを使ってみると、

countup = function(){
  var cnt = 0;
  return function(){console.log(++cnt);}
}
countup.bind()()();
countup.bind()()();

 
■実行結果

1
1

丸括弧が3つあるのは、

bindメソッドの引数
bindメソッドで返却される関数オブジェクトの引数
bindメソッドで返却される関数オブジェクトの実行

だよ。


 
ふむふむ。

2つのbindの呼び出しはそれぞれ別の関数オブジェクトの参照を返す

というのは別に、bindだからどうこうって話ではなくて、
単にメソッドを複数回呼び出したら、
そのたびにオブジェクトが生成されて返却されます
というだけの話か。

 
bindの返り値を変数に参照させておいても、
実行時に同じコンテキストを見ることはできない。

countup = function(){
  var cnt = 0;
  return function(){console.log(++cnt);}
}
var fn = countup.bind();
fn()();
fn()();

 
■実行結果

1
1


  
 
同じコンテキストを見たかったら、こう!

countup = function(){
  var cnt = 0;
  return function(){console.log(++cnt);}
}
var fn = countup.bind();
var gn = fn();
gn();
gn();

 
■実行結果

1
2


  
なるほどー。
用語がふわっとしててごめんなさい。

そしてピタゴラさん、ありがとう!