0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

JavaScript アロー関数とthis

Last updated at Posted at 2023-08-12

そもそもアロー関数って

ES2015(ES6)から利用可能になった新しい関数定義の構文です。
1文しかない関数の定義が簡素化できます。

定義例

引数も戻り値も無し
余談:戻り値?返り値?を追求した人いました💦

// いままで
const fnc1 = function () {
  console.log('SP');
}

// アロー
const arrowFnc1 = () => console.log('SP');

引数有り、戻り値無し

// いままで
const fnc2 = function (p1) {
  console.log(p1);
}

// アロー
const arrowFnc2 = (p1) => console.log(p1);

引数無し、戻り値有り

// いままで
const fnc3 = function () {
  return 'SP';
}

// アロー
const arrowFnc3 = () => 'SP';

引数有り、戻り有り

// いままで
const fnc4 = function (num) {
  return num * 2;
}

// アロー
const arrowFnc4 = num => num * 2;

複数引数有り、戻り有り

// いままで
const fnc5 = function (num,num2) {
  return num * num2;
}

// アロー
const arrowFnc5 = (num,num2) => num * num2;

まー、1行で書けてすっきりといった感じでしょうか。

もちろん、複数文の場合でもアロー関数定義できます。

// いままで
const fnc6 = function (num,num2) {
  const ans = num * num2;
  return ans;
}

// アロー
const arrowFnc5 = (num,num2) => {
  const ans = num * num2;
  return ans;
}

なんでもかんでもアロー関数定義していいわけではない。

制限事項

制限事項があります!

  • アロー関数には、this、arguments、super への結びつけがないので、メソッドとして使用することはできません。
  • アロー関数には new.target キーワードがありません。
  • アロー関数は、call、apply、bind のような、一般にスコープを確立することを前提としたメソッドには適していません。
  • アロー関数はコンストラクターとして使用することはできません。
  • アロー関数は本体内で yield を使用することはできません。

アロー関数式 JavaSript MDN

今回は制限事項のthisについて検証しようと思います。

アロー関数とthis

制限事項に「アロー関数には、this、arguments、super への結びつけがないので、メソッドとして使用することはできません。」
とありますが、
私は「this、arguments、super への結びつけがない」を「アロー関数ではthisは使えないのでメソッドの定義として使ってはいけない。」と理解しました。
しかし、この文だけだとよくわからないのでアロー関数でのthisについて検証します。

まずは、いままの構文でオブジェクトとメソッドを定義してみました。

// オブジェクト定義
const myObject = {
  name : 'SP 太郎',
  showName: function () {
    console.log(this.name);
  }
}

myObject.showName();

実行すると

SP 太郎

期待通りの表示がされました。なんの問題もありません。

アロー関数でメソッドを定義します。

// オブジェクト定義
const myObject = {
  name : 'SP 太郎',
  showName: () => {
    console.log(this.name);
  }
}

myObject.showName();

実行すると

Uncaught TypeError TypeError: Cannot read properties of undefined (reading 'name')

と、thisが使えないのでエラーになりました。

本当に使えないのか?ということでthisの値を出力してみました。

this確認
// オブジェクト定義
const myObject = {
  showName: () => {
    console.log(this);
  }
}

myObject.showName();

実行すると

undefined

と、this変数は未定義となっているので、使えないのか分かります。

本当に本当につかえないのか??
myObject.createSubObjectのメソッドはfunction関数定義で、
subObject.showNameのメソッドはアロー関数定義しました。

// オブジェクト定義
const myObject = {
  name: 'myObject',
  createSubObject: function() {
    return {
      name: 'subObject',
      showName: () => {
        console.log(this.name);
      }
    }
  },
  showName: function() {
    console.log(this.name);
  }
}

myObject.showName();

const subObject = myObject.createSubObject();
subObject.showName();

実行すると

myObject
myObject

あれ、エラーにならなかった。thisが使えた。。。。
しかし、結果がヘン。

subObject.showName();
の出力も「myObject」となっています。

ということで、
thisが使えないのではなく、thisって何?と評価タイミングがfunction関数とアロー関数で違う
と理解するのが正解だと思います。
上記の「this確認」ソースでthisがundefinedになったのは、myObjectがグローバル定義なので定義時にthisなんて存在しないからでしょう。

thisの評価タイミング

function関数(いままで): 関数が実行される時。
アロー関数: 関数が定義される時。

この評価タイミングを理解したうえでfunction関数にするかアロー関数にするか決めないと、わけのわかならいバグで
填まってしまうので気をつけましょう。

上記サンプルを解説すると
subObjectはcreateSubObjectメソッド実行時に定義しています。
createSubObjectメソッド実行時のthisは「myObject」です。
というこはsubObjectのshowName定義時のthisは「myObject」となります。
なので、subObjectのhowNameを実行した時のthisは「myObject」となり、myObject.nameの値が表示されることになります。

// オブジェクト定義
const myObject = {
  name: 'myObject',
  createSubObject: function() {

    // subObjectはcreateSubObjectメソッド実行時に定義しています。
    // createSubObjectメソッド実行時のthisは「myObject」です。
    return {
      name: 'subObject',
      // subObjectのshowName定義時のthisは「myObject」となります。
      showName: () => {
        // subObjectのhowNameを実行した時のthisは「myObject」となり、myObject.nameの値が表示されることになります。
        console.log(this.name);
      }
    }
  },
  showName: function() {
    console.log(this.name);
  }
}

subObject.showNameもfunction関数定義にしてみます。

// オブジェクト定義
const myObject = {
  name: 'myObject',
  createSubObject: function() {
    // このメソッド内のthisは「myObject」
    return {
      name: 'subObject',
      showName: function() {
        console.log(this.name);
      }
    }
  },
  showName: function() {
    console.log(this.name);
  }
}

myObject.showName();

const subObject = myObject.createSubObject();
subObject.showName();

subObject.showNameのthisも実行時に評価されるので、期待通りの結果となりました。

myObject
subObject

この検証から、クラスやオブジェクトのメソッドでは、アロー関数は使ってはいけない。となります。

Vue.jsのメソッドのマニュアル

アロー関数は this を介してコンポーネントのインスタンスにアクセスできないため、メソッドを宣言する際に使用することは避けてください。

と書いてあるのは、これらの理由からです。注意しましょう。

じゃ、どこで使う

Array.filterとかのコールバック関数とかで、無名メソッドを定義したいときに使うのがよいかと。

// いままで
const filteredList = list.filter(function (e) {
    return !e.del
});

// アロー関数
const filteredList = list.filter(e => !e.del);

以上です。

0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?