0
0

前回まではレキシカル環境とクロージャについてお話ししてきました。

今回はfunctionとarrow関数でのthisの挙動の変化について書いていこうかと思います。

今回はカイージくんは登場しません。予めご了承ください。

⇩カイージくんとのお勉強はこちらをご覧ください⇩

本題:thisとは

thisは関数やメソッドがどのオブジェクトから呼び出されたかを示します。

通常の関数では、thisは関数が呼び出されたコンテキストによって決まります。例えば、オブジェクトのメソッドとして呼び出された場合、thisはそのオブジェクトを指します。

const obj = {
    value: 42,
    regularMethod: function() {
        console.log(this.value); // this は obj を指す
    }
};

obj.regularMethod(); // 42

非strict モードでは、グローバルスコープでthisを使用すると、グローバルオブジェクト(ブラウザ環境では window)を指しますが、use strictモードではthisundefinedになります。

また、通常の関数として呼び出され時、以下のようになります。

const obj = {
    value: 42,
    method: function() {
        const innerFunction = function() {
            console.log(this.value); 
        };
        innerFunction();
    }
};

obj.method(); // グローバルオブジェクト(非 strict モード)、または `undefined`(strict モード)

同様に、上記の例では、innerFunctionは通常の関数として呼び出されるため、this はグローバルオブジェクトを指します(非 strict モードの場合)。strict モードでは undefined になります。


レキシカル環境は関数がどこで定義されたかによって決まるスコープチェーンである一方、アロー関数を使用した際はthis 自体はレキシカル環境(スコープチェーン)を作りません。

以下のコードを見てみましょう。

const obj = {
    value: 42,
    method: function() {
        const innerFunction = () => {
            console.log(this.value); // ここでの `this` は外側のスコープから継承される
        };
        innerFunction();
    }
};

obj.method(); // 42

アロー関数を使用した場合、this は外側のスコープ(この場合は method 内のスコープ)から継承され、obj を指します。

上記のコードを全てアロー関数で書いた場合はどうなるでしょうか。

const obj = {
    value: 42,
    method: () => {
        const arrowFunction = () => {
            console.log(this.value); // ここでの `this` はグローバルオブジェクト(非 strict モード)や `undefined`(strict モード)を指す
        };
        arrowFunction();
    }
};

obj.method(); // undefined (strict モードの場合) または グローバルオブジェクトの `value` (非 strict モードの場合)

CallBck関数との兼ね合い

通常の関数をコールバックとして使用すると、そのthisは呼び出し時のコンテキストに依存します。

以下で実行してみましょう。

const obj = {
    value: 42,
    method: function(callback) {
        callback();
    }
};

function regularFunction() {
    console.log(this.value);
}

obj.method(regularFunction); // undefined

regularFunctionthisはグローバルオブジェクトを指すので、残念ながら期待通りの結果にはなりませんでした。

ここで、アロー関数は定義されたときのthisを継承するので、コールバックとして使用してみましょう。

const obj = {
    value: 42,
    method: function(callback) {
        callback();
    }
};

const arrowFunction = () => {
    console.log(this.value);
};

obj.method(arrowFunction); // undefined

しかし、arrowFunctionが定義されたときのスコープにvalueが存在しないため、undefined になります。

そこで、正しい this を指すようにするためには、アロー関数をオブジェクトのメソッド内で定義してみましょう。

const obj = {
    value: 42,
    method: function() {
        const arrowFunction = () => {
            console.log(this.value); // this は obj を指す
        };
        arrowFunction();
    }
};

obj.method(); // 42

無事、辿り着けましたね。

もし、通常の関数でもコールバックで同じようにthisを求めたい時はどうすればいいのでしょうか。

ここではbindメソッドを使って明示的に繋げる方法をご紹介します。

bindメソッドは、定義された関数に対して、thisを代入できるメソッドです。また、その名の通り関数などをbind(紐づけ)することができます。

const obj = {
    value: 42,
    method: function(callback) {
        callback();
    }
};

function regularFunction() {
    console.log(this.value);
}

obj.method(regularFunction.bind(obj)); // 42

時間があれば、わかりやすい図とかも用意するかもしれません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0