web-dev-qa-db-fra.com

Les «fonctions de flèche» et les «fonctions» sont-elles équivalentes / échangeables?

Les fonctions de flèche dans ES2015 fournissent une syntaxe plus concise.

  • Puis-je remplacer toutes mes déclarations/expressions de fonction par des fonctions de flèche maintenant?
  • A quoi dois-je faire attention?

Exemples:

Fonction constructeur

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

// vs

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

Méthodes de prototype

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

// vs

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

Méthodes d'objet (littéral)

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

// vs

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

Rappels

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

// vs

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

Fonctions variadiques

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

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

tl; dr: Non! Les fonctions de flèche et les déclarations/expressions de fonction sont pas équivalent et ne peut pas être remplacé aveuglément.
Si la fonction que vous voulez remplacer ne pas utilisez this, arguments et n'est pas appelée avec new, alors Oui.


Comme souvent: cela dépend . Les fonctions des flèches ont un comportement différent de celui des déclarations/expressions de fonctions, examinons donc d'abord les différences:

1. Lexical this et arguments

Les fonctions fléchées n'ont pas leur propre liaison this ou arguments. Au lieu de cela, ces identificateurs sont résolus dans la portée lexicale comme toute autre variable. Cela signifie qu'à l'intérieur d'une fonction de flèche, this et arguments font référence aux valeurs de this et arguments dans l'environnement, la fonction de flèche est définie dans (c'est-à-dire "en dehors" de la fonction de flèche):

// 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

Dans le cas de l'expression de fonction, this fait référence à l'objet créé à l'intérieur de createObject. Dans le cas de la fonction de flèche, this fait référence à this de createObject lui-même.

Cela rend les fonctions de flèche utiles si vous devez accéder à la this de l’environnement actuel:

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

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

Notez que cela signifie également que n'est pas possible de définir la fonction this d'une fonction de flèche avec .bind ou .call.

Si vous n'êtes pas très familier avec this, envisagez de lire

2. Les fonctions de flèche ne peuvent pas être appelées avec new

ES2015 distingue les fonctions qui sont appellent et les fonctions qui sont construct . Si une fonction est constructible, elle peut être appelée avec new, c'est-à-dire new User(). Si une fonction est appelable, elle peut être appelée sans new (c'est-à-dire un appel de fonction normal).

Les fonctions créées par les déclarations/expressions de fonction sont à la fois constructibles et appelables.
Les fonctions (et méthodes) des flèches ne peuvent être appelées. Les constructeurs class ne sont constructibles que.

Si vous essayez d'appeler une fonction non appelable ou de construire une fonction non constructible, vous obtiendrez une erreur d'exécution.


Sachant cela, nous pouvons affirmer ce qui suit.

Remplaçable:

  • Fonctions qui n'utilisent pas this ou arguments.
  • Fonctions utilisées avec .bind(this)

non remplaçable:

  • Fonctions constructeur
  • Fonction/méthodes ajoutées à un prototype (car elles utilisent généralement this)
  • Fonctions variadiques (si elles utilisent arguments (voir ci-dessous))

Regardons cela de plus près en utilisant vos exemples:

Fonction constructeur

Cela ne fonctionnera pas car les fonctions de flèche ne peuvent pas être appelées avec new. Continuez à utiliser une déclaration/expression de fonction ou utilisez class.

Méthodes prototypes

Probablement pas, car les méthodes prototypes utilisent généralement this pour accéder à l'instance. S'ils n'utilisent pas this, vous pouvez le remplacer. Cependant, si vous vous souciez principalement de la syntaxe concise, utilisez class avec sa syntaxe de méthode concise:

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

  getName() {
    return this.name;
  }
}

Méthodes objet

De même pour les méthodes dans un objet littéral. Si la méthode veut référencer l'objet lui-même via this, continuez à utiliser des expressions de fonction ou utilisez la nouvelle syntaxe de la méthode:

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

Rappels

Ça dépend. Vous devez absolument le remplacer si vous aliasez le this extérieur ou si vous utilisez .bind(this):

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

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

Mais: Si le code qui appelle le rappel affecte explicitement this à une valeur spécifique, comme c'est souvent le cas avec les gestionnaires d'événements, en particulier avec jQuery, et le rappel utilise this (ou arguments), vous ne pouvez pas utiliser une fonction de flèche!

Fonctions variadiques

Les fonctions de flèches n'ayant pas leur propre arguments, vous ne pouvez pas les remplacer simplement par une fonction de flèches. Cependant, ES2015 introduit une alternative à l’utilisation de arguments: le paramètre de repos .

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

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

Question connexe:

Autres ressources:

625
Felix Kling

Regardez cet exemple Plnkr

La variable this est très différente timesCalled ne s'incrémente que de 1 à chaque appel du bouton. Ce qui répond à ma question personnelle:

.click( () => { } )

et

.click(function() { })

les deux créent le même nombre de fonctions lorsqu'elles sont utilisées dans une boucle que vous pouvez voir à partir du nombre de Guid dans le Plnkr.

3
abbaf33f