【forEach】意外と知らない?JavaScriptのthisの参照先について解説【アロー関数】

こんにちは~!

皆さんはJavaScriptで「this」を使っていますか?

いざ使おうと思ったときに限って「this」が想定通りの参照をしていなくて、焦った経験はありませんか?

今回は、そんな「this」の使い方を、間違えやすい例を交えつつ紹介します!

転ばぬ先の杖ということで、是非最後までお読みいただき、頭に入れておいてくださいね~!

thisの呼び出し例

例えば、下記のようなコードを書いてみました↓

console.log(this === window);
true

この結果から分かるように、通常、thisはグローバルオブジェクト「window」を指します。

では、こちらはどうでしょうか↓

function test() {
    console.log(this === window);
}
test();
true

関数の中のthisも同様に「window」を指します。

ではでは、こちらはどうでしょうか↓

function Test(txt) {
    if (this !== window) {
        this.txt = txt;
        console.log(this.txt);
    }
}
let test = new Test('Apple');
Apple

コンストラクタ内のthisは、インスタンス化された自身(Testの中)を指します。

Javaに馴染みがある人はピンとくるかもしれません。

最後に、こちらはどうでしょうか↓

let obj = {
    name: 'Apple',
    func: function() {
        console.log(this === obj);
        console.log(this.name);
    }
};
obj.func();
true
Apple

オブジェクトの中に関数がある場合、その関数の中のthisはオブジェクト自身を指します。

「this.name」のように記述すると、オブジェクト内の他のプロパティにアクセスできるので便利ですね。

JavaScriptでは一番よく使うような気がします。

間違えやすいthisの例

ここまでの呼び出し例を踏まえ、こちらの出力結果を考えてみましょう↓

let obj = {
    func: function(arr) {
        arr.forEach(function(v) {
            console.log(this === obj);
        });
        arr.forEach(v => console.log(this === obj));
        arr.forEach(v => {
            console.log(this === obj);
        });
    }
};
obj.func([1]);
false
true
true

…え??

let obj = {
    func: function(arr) {
        arr.forEach(function(v) {
            console.log(this === window);
        });
    }
};
obj.func([1]);
true

forEachの中がアロー関数だとthisは「obj」と一致するのに、functionだとthisは「window」と一致する!?

衝撃の事実発覚です。

まあでも、落ち着いて上の例を再度見直すと、functionだと「関数の中」ということになるので、
間違いではないんですよね。

しかしながら、ブラウザの互換性を考えながら(アロー関数が使えない環境で)書く必要がある場合だと、
このようなケースは混乱を招く恐れがあるので注意しましょう。

勿論、forEach以外でも同様の書き方をするもの(filter、map等)でも同じようになります。

forEachの第2引数でthisの参照先を指定する

実は、この「forEach-function問題」を解決し、forEachの中のfunction内でのthisを指定する方法があるのです。

このforEach、実は第2引数が存在するの、ご存知でしょうか?

第2引数(thisArg)に指定したものを、functionの中でのthisとして扱うことができるのです!

let obj = {
    func: function(arr) {
        arr.forEach(function(v) {
            console.log(this === obj);
        }, this);
    }
};
obj.func([1]);
true

このように、forEachの第2引数にthisを指定することで、functionの中でのthisも、
本来のthisが指す「obj」と同一になります。

勿論、forEach以外でも同様の書き方をするもの(filter、map等)でも同じように第2引数を指定可能です。

但し、逆にアロー関数だと第2引数に何を指定しても効かないので注意しましょう。

let obj = {
    func: function(arr) {
        arr.forEach(v => console.log(this === obj), window);
        arr.forEach(v => {
            console.log(this === obj);
        }, window);
    }
};
obj.func([1]);
true
true

まとめ

最後までお読みいただきありがとうございました!

オブジェクトの中のfunctionでthisを使うと、オブジェクト自身を参照できるので便利ですが、
更にその中でforEach等を使用する際は注意しましょう!

中身がアロー関数なら問題ありませんが、functionの場合は第2引数(thisArg)にthisを指定するのをお忘れなく!

それでは、今日はこの辺で。