無名関数とアロー関数のthisについて

要約

  • JSの普通の関数(名前あり関数)、無名関数内のthisは関数の呼び出し元(.(ドット)の前のオブジェクト)
  • 普通の関係、無名関数はbindを使えばthisを書き換えられる。
  • アロー関数のthisは宣言元のthisを示す。

本文

Java Script、jQueryについて引き続き勉強中なのでそれについてのメモ。

無名関数とアロー関数のthisについて分かったことがあったのでそれについてメモしておく。
本来、無名関数とアロー関数とthisの関数にjQueryAjaxは関係なのだが、jQueryAjaxを勉強中に気づいたことなので、jQueryAjaxを使ったコードになってしまっている。

やりたかったこと
jQuery リファレンス:jQuery.get
ここのサイトで勉強していて、jQueryAjaxの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を使わずにシンプルに書けるので、追加の引数を使いたい場合でなければこれを使えばいいかもしれない。