this. この便利でハマりどころの多い変数
Array.forEach / map 系 のthisArg が安定しない。
this 変数の紹介 this 変数の例
apply , call
window オブジェクト コールバック イベントハンドラ Array.forEach
個人的な結論 this はできるだけ避ける
調べたキッカケは Array.forEach
arr = ["A","B","C"] arr.forEach( function ( x ) { console.log ( this ) } )
このthisとして this => [“A”,“B”,“C”] を期待したわけです。
でも、this = window
arr = ["A","B","C"] arr.forEach( function ( x ) { console.log ( this ) } ) //=> Window //=> Window //=> Window
え?Windowなの?ちょっとまって。this 。そうか、そうだった。
"abc".replace( /a/, function(x){return this} ) //=>"[object Window]bc"
そういえばそうでした。this は関数の定義されたスコープから探されますよね。
this はその関数が実行(無名関数なら定義)されたスコープになる。
JSの変数はその実行スコープで決まる。
arr.forEach( function ( x ) { console.log ( this ) } ) // ここはWindowが実行するので this = window
実行主体がWindowなのでthis=window 、匿名関数なので定義されたタイミングでthis が決まる。
でもコレを見て欲しい(もう謎すぎてヤバイ)
アロー演算子と、function で指定し場合
実行環境は次の通り
ちなみに use strict すると動作が変わる
function の場合は use strict すれば次のような動作になる。
function を匿名関数で渡した場合
ソース | thisArg | use strict | 結果(this参照先) |
---|---|---|---|
arr.forEach( function(x){console.log(this);} ) | なし | なし | Window |
arr.forEach( function(x){“use strict”; console.log(this);},arr ) | arr | なし | arr |
arr.forEach( function(x){“use strict”; console.log(this);} ) | なし | あり | undefined |
arr.forEach( function(x){“use strict”; console.log(this);},arr )) | arr | あり | arr |
function を アロー演算子で渡した場合
ソース | thisArg | use strict | 結果 |
---|---|---|---|
arr.forEach( (x)=>{console.log(this);} ) | なし | なし | Window |
arr.forEach( (x)=>{console.log(this);}, arr ) | arr | なし | Window |
arr.forEach( (x)=>{“use strict”;console.log(this);}) | なし | あり | Window |
arr.forEach( (x)=>{“use strict”;console.log(this);}, arr ) | arr | あり | Window |
アロー演算子ではすべてが window(グローバル)です
forEach した場合ね
なにこれ揺れすぎ
ていうか、アロー演算子は this の値を、オブジェクト定義から参照する。
forEach引数 で this の値を指定しても、実行してるスコープが window なので強制的に Window (グローバルオブジェクト)になる。
アロー演算子でのforEachでは再束縛が出来なくなってる。。。。
もうね、this使うなとしか言いようが無い。
結論 this 使うな
暴論しておきたい。
参考資料
thisArgs について
this について
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
感想
無名関数のときに"use strict" した forEach で thisArg 無しならで undefined になる。これが個人的にはキッチリしてて嬉しいよね。いかにもuse strict っぽい。
アロー演算子の場合 this なかったら強制グローバルってのはどうも腑に落ちてこないというか。
コレクションでforEach中のthis は定義元のオブジェクトより、コレクション自身をしてして欲しいような気はする。
forEach がネストした時とか特に。
forEach が導入されて数年になるけど、あっさり thisArgs がなかったような扱いになってるのが寂しい所。
追記 2017-06-02
this が云々というより、thisArgs について語りたかった。アロー演算子の this はグローバルなので、 map( f , thisArg ) で thisArg を指定しても無視されるって話がメイン。
使うか使わないかとか、forEachの第三引数の話が使う使わないとか、this そのものの理解がとか、ブクコメに云々もについても言いたいことは、あるけれど 現状 use stricit してるかチェックを油断してるとまじthisめんどーってなる。コーディング規約が決まった同一社コードばかり見てるわけじゃないんで。油断するなよ的な、そんな話