2021年2月1日

アロー関数の再考

アロー関数を再考してみましょう。

アロー関数は、小さなものを書くための「省略記法」だけではありません。非常に具体的で便利な機能がいくつかあります。

JavaScriptには、小さな関数を書いて他の場所で実行する必要がある状況がたくさんあります。

例えば

  • arr.forEach(func)funcは、配列の各要素に対してforEachによって実行されます。
  • setTimeout(func)funcは、ビルトインスケジューラによって実行されます。
  • …他にもあります。

関数を生成してどこかに渡すことは、JavaScriptのまさに本質です。

そして、そのような関数では、通常、現在のコンテキストを離れたくありません。そこでアロー関数が役立ちます。

アロー関数には「this」がない

オブジェクトメソッド、"this"」の章で覚えているように、アロー関数にはthisがありません。thisにアクセスした場合、外部から取得されます。

例えば、オブジェクトメソッド内で反復処理するために使用できます。

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(
      student => alert(this.title + ': ' + student)
    );
  }
};

group.showList();

ここでforEachではアロー関数を使用しているので、その中のthis.titleは、外部メソッドshowListのものとまったく同じです。つまり、group.titleです。

「通常の」関数を使用した場合、エラーが発生します。

let group = {
  title: "Our Group",
  students: ["John", "Pete", "Alice"],

  showList() {
    this.students.forEach(function(student) {
      // Error: Cannot read property 'title' of undefined
      alert(this.title + ': ' + student);
    });
  }
};

group.showList();

このエラーは、forEachがデフォルトでthis=undefinedで関数を実行するため、undefined.titleへのアクセスが試みられるため発生します。

アロー関数では、単にthisを持っていないため、これは影響しません。

アロー関数は`new`で実行できません

thisを持たないということは、当然、別の制限を意味します。アロー関数はコンストラクタとして使用できません。newで呼び出すことはできません。

アロー関数とbind

アロー関数=>と、.bind(this)で呼び出された通常の関数との間には微妙な違いがあります。

  • .bind(this)は、関数の「バインドされたバージョン」を作成します。
  • アロー=>はバインドを作成しません。関数は単にthisを持っていないだけです。thisの検索は、通常の変数の検索と同じ方法で行われます。つまり、外部のレキシカル環境です。

アロー関数には「arguments」がない

アロー関数にはarguments変数もありません。

これはデコレータにとって素晴らしいことで、現在のthisargumentsで呼び出しを転送する必要がある場合に役立ちます。

例えば、defer(f, ms)は関数を取得し、その関数の周りにラッパーを返し、呼び出しをmsミリ秒遅延させます。

function defer(f, ms) {
  return function() {
    setTimeout(() => f.apply(this, arguments), ms);
  };
}

function sayHi(who) {
  alert('Hello, ' + who);
}

let sayHiDeferred = defer(sayHi, 2000);
sayHiDeferred("John"); // Hello, John after 2 seconds

アロー関数を使用しない場合、次のようになります。

function defer(f, ms) {
  return function(...args) {
    let ctx = this;
    setTimeout(function() {
      return f.apply(ctx, args);
    }, ms);
  };
}

ここでは、setTimeout内の関数がそれらを取得できるように、追加の変数argsctxを作成する必要がありました。

まとめ

アロー関数

  • thisを持たない
  • argumentsを持たない
  • newで呼び出すことができない
  • また、superもありませんが、まだ学習していません。「クラス継承」の章で学習します。

これは、独自の「コンテキスト」を持たない短いコード断片を目的としており、むしろ現在のコンテキストで動作するためです。そして、そのユースケースで本当に輝きます。

チュートリアルマップ

コメント

コメントする前にこれを読んでください…
  • 改善点に関する提案がある場合は、コメントする代わりにGitHub issueまたはプルリクエストを送信してください。
  • 記事の内容が理解できない場合は、詳しく説明してください。
  • 数語のコードを挿入するには<code>タグを使用し、複数行の場合は<pre>タグで囲み、10行を超える場合はサンドボックス(plnkrjsbincodepen…)を使用してください。