無名関数とアロー関数のthisについて
要約
- JSの普通の関数(名前あり関数)、無名関数内の
this
は関数の呼び出し元(.(ドット)の前のオブジェクト) - 普通の関係、無名関数はbindを使えばthisを書き換えられる。
- アロー関数のthisは宣言元のthisを示す。
本文
Java Script、jQueryについて引き続き勉強中なのでそれについてのメモ。
無名関数とアロー関数のthisについて分かったことがあったのでそれについてメモしておく。
本来、無名関数とアロー関数とthis
の関数にjQueryとAjaxは関係なのだが、jQueryとAjaxを勉強中に気づいたことなので、jQueryとAjaxを使ったコードになってしまっている。
やりたかったこと
jQuery リファレンス:jQuery.get
ここのサイトで勉強していて、jQueryのAjaxのgetでクリックした要素の次の要素のデータを編集したいと思った。
しかし、jQuery.get
はコールバック関数を呼び出すのだがそのコールバック関数内ではthis
はまた別のものになってしまっている。
$(function() { $("#clickArea").click(function(){ $.get("data/simple.txt", getFunc) }); function getFunc(myData, myStatus){ $(this).next().html(myData);//ここでのthisは#clickArea要素ではない。 $("body").append("myStatus = " + myStatus); }; });
上のコードのコメントで言っているように、コールバック関数内のthisは意図した#clickArea
要素ではなく、関数呼び出し元のajax
オブジェクトになってしまっている。
どうにかして、コールバック関数に宣言元のthis
を何らかの形で渡せればいいのだが...(伏線)
解決策.1: bindを使う
Javascriptのcall/apply関数のプロっぽい使い方 〜 JSおくのほそ道 #014 - Qiita
Javascriptのbind関数と部分適用 〜 JSおくのほそ道 #015 - Qiita
ここら辺を読んでcall,apply,bindを理解した。
bindを使えばthisを任意に書き換えられるらしい。つまりこうだ。
$(function() { $("#clickArea").click(function(){ $.get("data/simple.txt", getFunc.bind(this))//コールバック関数を.bind(this)をつけて指定 }); function getFunc(myData, myStatus){ $(this).next().html(myData);//ここでのthisは#clickArea要素。 $("body").append("myStatus = " + myStatus); }; });
これでうまく動く。
また、bindは無名関数の{}
の最後に.bind
とつければ、無名関数の場合も使える。
$(function() { $("#clickArea").click(function(){ $.get("data/simple.txt", function (myData, myStatus){ $(this).next().html(myData); $("body").append("myStatus = " + myStatus); }.bind(this));//{}の最後の.bindとつければOK }); });
そして補足だが、bind
は第二引数以降に追加の引数を指定することができる。追加の引数は元から渡される引数(ajaxのgetの場合は、data, textStatus, xhrとかの引数)の前に追加される。コードで示すと、
$(function() { $("#clickArea").click(function(){ $.get("data/simple.txt", getFunc.bind(this,"Hello"))//引数"Hello"を追加 }); function getFunc(greeting, myData, myStatus){//greetingで追加の引数を受け取る。 $(this).next().html(myData); $("body").append("myStatus = " + myStatus); console.log(greeting);//Helloと表示される }; });
となる。
解決策2: アロー関数を使う
アロー関数内のthisは宣言元のthisをそのまま引き継ぐらしい。(アロー関数ではbindは使えないらしい)
$(function() { $("#clickArea").click(function(){ $.get("data/simple.txt", (myData, myStatus)=>{ $(this).next().html(myData);//ここでのthisは#clickArea要素。 $("body").append("myStatus = " + myStatus); }); }); });
bindを使わずにシンプルに書けるので、追加の引数を使いたい場合でなければこれを使えばいいかもしれない。