おひさしぶりです。アインです。今日はthis
のロジックを説明します
最初に、このコードサンプルを一緒に見てみましょう。
1 2 3 4 5 6 7 8 9 |
var x = { n:10 , p: function(){ console.log(this.n); } }; x.p(); |
このコードを実装すると結果は
1 2 |
10 |
今回はさっきのObjectはFunctionの中に実装してみると
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
function f(i) { return { n:i, p: function(){ console.log(this.n); } }; } for(var i=0;i<4;i++) { setTimeout(f(i).p,3000); } |
今回のコードを実装すると、
1 2 3 4 5 |
undefined undefined undefined undefined |
これの原因は、オブジェクトのメッソドを コピーする時 とか、関数に渡す時 とか、 オブジェクトバインディングをなくなります。ほとんどの場合、this
の値は、関数の呼ばれ方によって決定されます。これは実行時に割り当てできず、関数が呼び出されるたびに異なる可能性があります。
1 2 |
x.p(); // p はxからよばれました。this の値はxです。 |
オブジェクトがない場合、変数を呼ばれると、this
はなくなります,代わりにwindow
を使われます。
1 2 3 |
var p = x.p; p(); // p はオブジェクトからよばれなかった。thisの値はwindow。 |
また、関数に渡す時も
1 2 3 4 5 6 7 |
function myFunctionCaller (fn) { fn(); // fnはオブジェクトからよばれなかった。thisの値はwindow。 } myFunctionCaller(x.p); |
あなたが関数を呼び出していないときは、それはあまり明白になりません。JavascriptにはいろいろAPIは渡した変数を呼ばれてくれます。例えばArray.forEach
, setTimeout
。
1 2 3 |
setTimeout(x.p, 3000); // x は p と一緒にいかない. setTimeout は `p()` だけを呼びます。, `x.p()` じゃない // ... ですから、thisの値はwindow |
治し方
書き直すは複数の方法がありますが、bindのfunctionを使うならいいです
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function f(i) { var obj = { n:i }; function p(){ console.log(this.n); } obj.p = p.bind(obj); return obj; } for(var i=0;i&lt;4;i++) { setTimeout(f(i).p,3000); } |