Fonctions Fléchées en JavaScript

Les fonctions fléchées, introduites dans la spécification ECMAScript 6 (ES6), offrent une syntaxe plus concise pour la définition de fonctions en JavaScript, s'apparentant à des fontcions anonymes.

Syntaxe Complète

La forme complète est similaire aux fonctions anonymes traditionnleles, mais elle omet le mot-clé function.

const additionner = (a, b) => {
  console.log(`Les valeurs sont : ${a}, ${b}`); // Les valeurs sont : 1, 2
  return a + b;
};
console.log(additionner(1, 2)); // 3

// Équivalent à :
const additionnerNormal = function(a, b) {
  console.log(`Les valeurs sont : ${a}, ${b}`); // Les valeurs sont : 1, 2
  return a + b;
};
console.log(additionnerNormal(1, 2)); // 3

Paramètres Simplifiés

Si un seul paramètre est présent, les parenthèses peuvent être omises. Pour zéro ou plus de deux paramètres, les parenthèses sont obligatoires.

const doubler = nombre => {
  console.log(`Le nombre est : ${nombre}`); // Le nombre est : 5
  return nombre * 2;
};
console.log(doubler(5)); // 10

// Équivalent à :
const doublerNormal = function(nombre) {
  console.log(`Le nombre est : ${nombre}`); // Le nombre est : 5
  return nombre * 2;
};
console.log(doublerNormal(5)); // 10

Corps de Fonction Simplifié

Lorsque le corps de la fonction ne contient qu'une seule instruction, les accolades {} peuvent être omises. L'instruction sera alors implicitement retournée.

const comparer = (x, y) => x - y;
const nombres = [5, 1, 4, 2, 3];
const nombresTries = nombres.sort(comparer);
console.log(nombresTries); // [1, 2, 3, 4, 5]

// Équivalent à :
const comparerNormal = function(x, y) { return x - y; };
const nombres2 = [5, 1, 4, 2, 3];
const nombresTries2 = nombres2.sort(comparerNormal);
console.log(nombresTries2); // [1, 2, 3, 4, 5]

Syntaxe Complètement Simplifiée

Lorsque les deux conditions précédentes sont remplies (un seul paramètre et un corps de fonction d'une seule instruction), les parenthèses et les accolades peuvent être toutes deux omises.

const multiplierParDeux = val => val * 2;
console.log(multiplierParDeux(7)); // 14

// Équivalent à :
const multiplierParDeuxNormal = function(val) { return val * 2; };
console.log(multiplierParDeuxNormal(7)); // 14

Retour d'Objets Littéraux

Lorsqu'une fonction fléchée simplifiée doit retourner un objet littéral, celui-ci doit être enveloppé dans des parenthèses (). Sans cela, les accolades {} seraeint interprétées comme le début et la fin du corps de la fonction.

const creerObjet = id => ({ identifiant: id, valeur: id * 2 });
console.log(creerObjet(3)); // { identifiant: 3, valeur: 6 }

// Équivalent à :
const creerObjetNormal = function(id) { return { identifiant: id, valeur: id * 2 }; };
console.log(creerObjetNormal(3)); // { identifiant: 3, valeur: 6 }

Absence de Contexte this Propre

Les fonctions fléchées ne possèdent pas leur propre contexte this. Lors de l'utilisation de this à l'intérieur d'une fonction fléchée, il hérite de la valeur de this de son environnement englobant (lexical scope). Elles ne créent pas de nouveau this et ne peuvent pas modifier la valeur de this via apply, call ou bind.

const monObjet = {
  nom: 'Objet Global',
  methodeFlechee: () => {
    console.log(`this dans la méthode fléchée : ${this.nom}`); // undefined ou contexte global
  },
  methodeNormale: function() {
    console.log(`this dans la méthode normale : ${this.nom}`); // Objet Global
    const methodeFlecheeInterne = () => {
      console.log(`this dans la méthode fléchée interne : ${this.nom}`); // Objet Global
    };
    methodeFlecheeInterne();
  }
};

monObjet.methodeFlechee();
monObjet.methodeNormale();

Cette caractéristique est particulièrement utile pour résoudre les problèmes courants de contexte this dans les fonctions de rappel.

Problème Classique de Contexte

const objContexte = {
  valeur: 10,
  demarrer: function() {
    console.log(`Valeur initiale dans run: ${this.valeur}`); // 10
    setTimeout(function() {
      // Le contexte 'this' ici est celui de setTimeout (souvent l'objet window ou undefined en mode strict)
      console.log(`Valeur dans setTimeout (normal): ${this.valeur}`); // undefined
    }, 1000);
  }
};
objContexte.demarrer();

Solution avec une Variable Intermédiaire

const objContexteVar = {
  valeur: 10,
  demarrer: function() {
    const that = this; // Capture du contexte 'this'
    setTimeout(function() {
      console.log(`Valeur dans setTimeout (avec 'that'): ${that.valeur}`); // 10
    }, 1000);
  }
};
objContexteVar.demarrer();

Solution avec bind

const objContexteBind = {
  valeur: 10,
  demarrer: function() {
    const callback = function() {
      console.log(`Valeur dans setTimeout (avec bind): ${this.valeur}`); // 10
    };
    setTimeout(callback.bind(this), 1000); // Lier explicitement 'this'
  }
};
objContexteBind.demarrer();

Solution avec Fonction Fléchée

Les fonctions fléchées simplifient grandement ce scénario, car elles héritent le this de leur portée englobante.

const objContexteFleche = {
  valeur: 10,
  demarrer: function() {
    // La fonction fléchée hérite le 'this' de la méthode demarrer
    setTimeout(() => {
      console.log(`Valeur dans setTimeout (fléchée): ${this.valeur}`); // 10
    }, 1000);
  }
};
objContexteFleche.demarrer();

Absence d'Objet arguments Propre

Les fonctions fléchées ne disposent pas de leur propre objet arguments. Si vous y accédez, il s'agira d'une référence à l'objet arguments de la portée englobante.

function fonctionPrincipale(a, b) {
  console.log(`Arguments de fonctionPrincipale: ${arguments.length}`); // 2
  
  const fonctionFlecheeInterne = (...args) => {
    // Utilise les arguments de fonctionPrincipale s'ils sont disponibles dans la portée, sinon ses propres arguments s'ils sont passés.
    // Dans ce cas, si on appelle ss1(3), 'arguments' fait référence à ceux de fonctionPrincipale.
    console.log(`Arguments de fonctionFlecheeInterne (simulés): ${args}`); // 1, 2
  };
  
  const fonctionNormaleInterne = function(...args) {
    // 'arguments' fait référence aux arguments de cette fonction interne.
    console.log(`Arguments de fonctionNormaleInterne: ${args}`); // 3
  };
  
  fonctionFlecheeInterne(a, b); // Passe les arguments originaux
  fonctionNormaleInterne(3);  // Passe de nouveaux arguments
}
fonctionPrincipale(1, 2);

Non utilisables comme Constructeurs

Les fonctions fléchées ne peuvent pas être utilisées comme constructeurs avec l'opérateur new. Une tentative entraînera une erreur.

const MaFonctionFlechee = () => {};
try {
  new MaFonctionFlechee();
} catch (e) {
  console.error(e.message); // MaFonctionFlechee is not a constructor
}

Absence de Propriété prototype

Étant donné qu'elles ne peuvent pas être utilisées comme constructeurs, les fonctions fléchées n'ont pas de propriété prototype.

const fonctionSimple = () => {};
console.log(fonctionSimple.prototype); // undefined

Non utilisables comme Générateurs

Les fonctions fléchées ne peuvent pas être utilisées comme fonctions génératrices. Le mot-clé yield n'est généralement pas applicable à l'intérieur d'une fonction fléchée, sauf si elle est imbriquée dans une fonction qui autorise yield.

Étiquettes: JavaScript ES6 Fonctions Fléchées Fonctions Anonymes this

Publié le 30 juillet à 16h59