「アロー関数」と「関数」は同等ですか? 質問する

「アロー関数」と「関数」は同等ですか? 質問する

ES2015 の矢印関数は、より簡潔な構文を提供します。

  • すべての関数宣言/式を矢印関数に置き換えることはできますか?
  • 何に注意すればいいでしょうか?

例:

コンストラクタ関数

function User(name) {
  this.name = name;
}

// vs

const User = name => {
  this.name = name;
};

プロトタイプ手法

User.prototype.getName = function() {
  return this.name;
};

// vs

User.prototype.getName = () => this.name;

オブジェクト(リテラル)メソッド

const obj = {
  getName: function() {
    // ...
  }
};

// vs

const obj = {
  getName: () => {
    // ...
  }
};

コールバック

setTimeout(function() {
  // ...
}, 500);

// vs

setTimeout(() => {
  // ...
}, 500);

可変長関数

function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// vs
const sum = (...args) => {
  // ...
};

ベストアンサー1

tl;dr: いいえ!矢印関数と関数宣言/式は同等ではないため、盲目的に置き換えることはできません。
置き換えたい関数が を使用せずthisargumentsで呼び出されない場合はnew、そうです。


よくあることですが、それは状況によります。矢印関数は関数宣言/式とは異なる動作をするため、まずはその違いを見てみましょう。

1. 語彙thisarguments

this矢印関数には独自のまたはバインディングはありませんarguments。代わりに、それらの識別子は他の変数と同様にレキシカル スコープ内で解決されます。つまり、矢印関数内では、thisとは矢印関数が定義されている環境(つまり、矢印関数の「外部」) 内のとargumentsの値を参照します。thisarguments

// Example using a function expression
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: function() {
      console.log('Inside `bar`:', this.foo);
    },
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

// Example using a arrow function
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

関数式の場合、thisは 内で作成されたオブジェクトを参照しますcreateObject。矢印関数の場合、は 自身のthisを参照します。thiscreateObject

thisこれにより、現在の環境にアクセスする必要がある場合に矢印関数が役立ちます。

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

これは、矢印関数の をまたはで設定できないことも意味することに注意してくださいthis.bind.call

にあまり詳しくない場合はthis、以下をお読みください。

2. 矢印関数は次のように呼び出すことはできません。new

ES2015 では、呼び出し可能な関数と構築可能な関数が区別されます。関数が構築可能な場合は、 を使用して呼び出すことができますnew(つまり、 )。new User()関数が呼び出し可能な場合は、 を使用せずに呼び出すことができますnew(つまり、通常の関数呼び出し)。

関数宣言/式を通じて作成された関数は、構築可能かつ呼び出し可能です。
矢印関数 (およびメソッド) は呼び出しのみ可能です。classコンストラクターは構築のみ可能です。

呼び出し不可能な関数を呼び出そうとしたり、構築不可能な関数を構築しようとしたりすると、実行時エラーが発生します。


これを踏まえて、次のように述べることができます。

交換可能:

  • thisまたは を使用しない関数arguments
  • 使用される関数.bind(this)

交換不可:

  • コンストラクタ関数
  • プロトタイプに追加された関数/メソッド(通常は を使用するためthis
  • 可変引数関数(使用する場合arguments(下記参照))
  • ジェネレータ関数は、以下のfunction*表記を必要とする。

あなたの例を使ってこれを詳しく見てみましょう:

コンストラクタ関数

矢印関数は では呼び出せないため、これは機能しませんnew。関数宣言/式を使い続けるか、 を使用してくださいclass

プロトタイプ手法

プロトタイプ メソッドは通常、インスタンスにアクセスするために を使用するため、おそらくそうではありませんthis。 を使用しない場合は、 を置き換えることができます。ただし、簡潔な構文を主に重視する場合は、の簡潔なメソッド構文をthis使用します。class

class User {
  constructor(name) {
    this.name = name;
  }
  
  getName() {
    return this.name;
  }
}

オブジェクトメソッド

オブジェクトリテラル内のメソッドについても同様です。メソッドが を介してオブジェクト自体を参照する場合はthis、関数式を使い続けるか、新しいメソッド構文を使用します。

const obj = {
  getName() {
    // ...
  },
};

コールバック

それは状況によります。外側にエイリアスを設定している場合thisや、以下を使用している場合は、必ず置き換える必要があります。.bind(this)

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

ただし、コールバックを呼び出すコードがthis特定の値を明示的に設定する場合 (イベント ハンドラー、特に jQuery の場合によくあることですが)、およびコールバックがthis(またはarguments) を使用する場合、矢印関数は使用できません。

可変長関数

アロー関数には独自の がないためarguments、単純にアロー関数で置き換えることはできません。しかし、ES2015では を使用する代わりにarguments残りのパラメータ

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

関連する質問:

その他のリソース:

おすすめ記事