IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tutoriel présentant les nouveautés ECMAScript 6

Les variables et les fonctions


précédentsommaire

III. ES6 : les fonctions

Les fonctions sont les pièces maîtresses de JavaScript, à tel point qu'il existe même une programmation fonctionnelle.

Dans ce chapitre on va voir les nouveautés de ES6 pour les fonctions : noms, portée et fonctions fléchées.

III-A. Le nom des fonctions

Il est souvent utile de connaître le nom d'une fonction, ne serait-ce que lorsqu'on débogue du code. Avec ES5 il existe une propriété name qui contient ce nom (mais non pris en charge par tous les moteurs) :

 
Sélectionnez
1.
2.
3.
4.
function toto() {function toto() {};
var titi = function() {};
console.log(toto.name);  // toto
console.log(titi.name);  // titi

Quel est le nom d'une fonction anonyme ?

Par principe elle n'en a justement aucun parce qu'on n'a jamais à l'appeler, mais on peut l'affecter à une variable comme on l'a fait pour titi ci-dessus, dans ce cas elle porte le nom de la variable.

Avec ES6 toutes les fonctions ont un nom, donc la propriété name est toujours renseignée.

III-A-1. Les méthodes d'un objet

On peut se demander comment sont nommées les méthodes d'un objet. Voyons avec un exemple :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
let objet = {
    methode1() {},
    methode2: function () {}
};
console.log(objet.methode1.name); // methode1
console.log(objet.methode2.name); // methode2

Très logiquement on se retrouve avec le nom des méthodes.

Mais il y a le cas particulier des accesseurs (getters) et mutateurs (setters) :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
let objet = {
    get name() {},
    set name(value) {}
};
console.log((Object.getOwnPropertyDescriptor(objet, 'name').get).name); // "get name"
console.log((Object.getOwnPropertyDescriptor(objet, 'name').set).name); // "set name"

On voit que le nom commence avec set ou get.

Le nom d'un fonction a seulement un caractère informatif, il ne peut pas être utilisé dans le code. Sa principale utilité concerne le débogage.

III-B. Portée des fonctions

Avec ES5 en mode strict on ne peut pas placer une fonction dans un bloc :

 
Sélectionnez
{
    function f() {};
}

Par contre on peut avoir une expression de fonction :

 
Sélectionnez
{
    var f = function () {};
}

Avec ES6 on peut placer une fonction dans un bloc, elle est alors accessible uniquement dans ce bloc.

Et évidemment dans le cas d'une expression de fonction on va utiliser let pour limiter la portée au bloc.

III-C. Les fonctions fléchées

Abordons maintenant une des nouveautés les plus intéressantes de ES6 : les fonctions fléchées.

Comme leur nom l'indique on utilise une nouvelle syntaxe avec une flèche =>‌

On va voir qu'on a deux avantages par rapport aux expressions de fonctions classiques :

  • une syntaxe courte ;
  • un this lexical.

III-C-1. La syntaxe

Mais commençons par voir la syntaxe d'une fonction fléchée :

 
Sélectionnez
let resultat = valeur => valeur;
console.log(resultat(2));  // 2

J'ai défini la fonction resultat, je lui transmet une valeur et elle se contente de retourner cette valeur.

Bon, elle ne sert à rien ma fonction mais c'est juste pour voir la syntaxe. En version ES5 on aurait ceci :

 
Sélectionnez
var resultat = function resultat(valeur) {
  return valeur;
};

On va aller un peu plus loin en utilisant deux paramètres :

 
Sélectionnez
let resultat = (valeur1, valeur2) => valeur1 * valeur2;
console.log(resultat(2, 3));  // 6

Cette fois ma fonction est utile, elle retourne le produit des deux valeurs transmises. En version ES5 on aurait ceci :

 
Sélectionnez
var resultat = function resultat(valeur1, valeur2) {
  return valeur1 * valeur2;
};

On voit que la syntaxe est bien plus concise et claire avec une fonction fléchée.

Si on a un peu plus de traitement à effectuer alors on utilise des accolades et return :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
let resultat = (valeur1, valeur2) => {
  if(valeur1 > valeur2) {
    return valeur1;
  } else {
       return valeur2; 
  }
}
console.log(resultat(2, 3));  // 3

III-C-2. La valeur de this

Avec ES5 la valeur de this est déterminée de façon dynamique et dépend du contexte (constructeur, fonction, méthode…), ce qui n'est pas sans surprises et difficultés.

Avec ES6 la valeur de this est déterminée de façon lexicale, autrement dit elle est déterminée par le contexte englobant.

Bon, si ce n'est pas très clair on va prendre des exemples !

Je veux créer un indexeur avec le choix du numéro de départ, voici le code que j'essaie :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
function Numerote(depart) {
    this.depart = depart;
}
Numerote.prototype.numeroteTableau = function (tableau) { 
       return tableau.map(function (x) {
        return x + this.depart++;
    });
};

var num = new Numerote(5);
console.log(num.numeroteTableau(['a', 'b', 'c']));// true

Mais mon code ne fonctionne pas parce que le this à l'intérieur de la fonction masque le this englobant.

Quand on tombe sur ce genre de situation on mémorise le this juste avant la fonction avec une autre variable :

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
function Numerote(depart) {
    this.depart = depart;
}
Numerote.prototype.numeroteTableau = function (tableau) { 
      let that = this;
       return tableau.map(function (x) {
        return x + that.depart++;
    });
};

var num = new Numerote(5);
console.log(num.numeroteTableau(['a', 'b', 'c']));  // ["a5","b6","c7"]

C'est efficace même si ce n'est pas vraiment élégant…

Une autre solution (qui fonctionne avec ECAMScript 5.1) consiste à lier this à la fonction :

 
Sélectionnez
return tableau.map(function (x) {
    return x + this.depart++;
}.bind(this));

Avec ES6 il suffit d'utiliser une méthode fléchée :

 
Sélectionnez
1.
2.
3.
4.
5.
Numerote.prototype.numeroteTableau = function (tableau) { 
       return tableau.map((x) => {
        return x + this.depart++;
    });
};

Là, this a la référence correcte et tout fonctionne !

III-D. En résumé

  • Avec ES6 toutes les fonctions sont automatiquement nommées pour faciliter le débogage.
  • Avec ES6 une fonction dans un bloc a comme portée ce bloc.
  • Les fonctions fléchées simplifient la syntaxe et permettent d'avoir un this lexical.

précédentsommaire

Copyright © 2018 Laravel. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.