Il n’y a pas de meilleur moyen de s’assurer que vous comprenez comment quelque chose fonctionne que de construire votre propre version à partir de zéro. Dans cet article, nous allons le faire en créant nos propres versions des méthodes de tableau javascript Map, Reduce, Sort, et Filter from scratch.

En combinant les fonctions fléchées ES6 avec les fonctions JavaScript Array, vous pouvez écrire du code extrêmement puissant et propre ! Et si vous pouvez écrire des fonctions de tableau JavaScript à partir de zéro, vous aurez une meilleure compréhension de leur fonctionnement !

Le plan

Bien que ce ne soit pas recommandé, vous pouvez écraser les fonctions JavaScript assez facilement (nous le faisons ici uniquement à des fins de démonstration !).

Les fonctions de tableau JavaScript font partie du prototype Array, tout comme les fonctions d’une classe en Php, par exemple. Nous pouvons ainsi écraser les fonctions du prototype. Notez que j’imprime un message à la console pour prouver que la fonction a été écrasée lorsque nous appelons Array.prototype.map.

const myCustomMapFunction = () => {
    console.log("My Custom Map Function!");
}
Array.prototype.map = myCustomMapFunction;

Comment fonctionnent les méthodes de tableau JavaScript ?

Les méthodes JavaScript Array s’appuient fortement sur les fonctions ES6 Arrow. Si vous n’êtes pas familier avec les fonctions fléchées ES6, je vous recommande de lire mon article sur les fonctions fléchées javascript.

Commençons par un exemple. Supposons que vous vouliez itérer à travers un tableau, incrémenter chaque élément (un nombre) par un, et retourner le nouveau tableau. C’est un exemple de ce que fait la fonction Map. Dans le passé, vous auriez dû faire plusieurs choses pour y parvenir.

  • initialiser un nouveau tableau vide
  • itérer à travers chaque élément du tableau d’origine
  • modifier cet élément et mettre la valeur modifiée dans le nouveau tableau

Le code ressemblerait à ceci :

const arr =[1,2,3];
const newArray = [];

for (let i = 0; i < arr.length; i++) {
   newArray[i] = arr[i] + 1;
}
return newArray;

Pas si mal, mais avec la fonction Map Array intégrée, vous pouvez le faire en une seule ligne :

return arr.map( element => ++element);

Chacune des fonctions de tableau que nous allons couvrir accepte une fonction comme paramètre. Ils vont itérer à travers chaque élément du tableau (comme nous l’avons fait ci-dessus) et appeler cette fonction pour déterminer ce qu’il faut faire avec chaque élément. Après l’itération à travers chaque élément et l’appel de la fonction de rappel, un nouveau tableau ou élément (voir réduire ci-dessous) sera retourné.

La fonction javascript Map

Map itère à travers chaque élément, le transforme d’une manière ou d’une autre, l’ajoute à un nouveau tableau, et retourne le nouveau tableau.

Ok, en fait, construisons quelque chose et commençons par Map puisque nous l’avons mentionné plus haut. Commençons par écraser la fonction map pour prouver que nous pouvons remplacer avec succès la fonction originale.

const myCustomMapFunction = ( callback ) => {
    console.log("My Custom Map Function!");
}
Array.prototype.map = myCustomMapFunction;

const arr = [1,2,3];

arr.map();

Si vous exécutez ce code, vous devriez voir les logs appropriés dans la console. Bon début ! Maintenant nous pouvons ajouter la boucle for et imprimer chaque élément. Puisque le tableau lui-même est ce que l’on appelle la méthode, on accède à ce tableau en référençant “this”.

const myCustomMapFunction = function ( callback ) {
    //this refers to the array
    for (let i = 0; i < this.length; i++) {
        console.log(this[i]);
    }

}

Maintenant, nous devons effectuer n’importe quelle transformation requise en appelant la fonction de rappel. Lorsque nous le ferons, nous lui passerons deux choses, l’élément actuel et l’indice actuel.

const myCustomMapFunction = function ( callback ) {
    //this refers to the array
    for (let i = 0; i < this.length; i++) {
        const transformedElement = callback([this[i], i);
    }

}

Enfin, ajoutez les éléments transformés à un nouveau tableau et renvoyez ce tableau.

const myCustomMapFunction = function ( callback ) {
    const newArray = [];

    for (let i = 0; i < this.length; i++) {
        newArray[i] = callback(this[i], i);
    }

return newArray;
}

Voilà comment fonctionne la méthode javascript map; Allons voir les suivantes

La méthode javascript Filter

Filter retourne un nouveau tableau d’éléments filtrés à partir du tableau original.

Commençons par écraser notre méthode de filtrage.

const myCustomFilterFunction = () => {
    console.log("My Custom Filter Function!");
}
Array.prototype.filter = myCustomMapFunction;

Maintenant, configurons la boucle for pour itérer à travers chaque élément.

const myCustomFilterFunction = function ( callback ) {
    const newArray = [];

    for (let i = 0; i < this.length; i++) {
        console.log(this[i]);
    }

}

A l’intérieur de la boucle for, nous devons décider d’ajouter ou non chaque élément au nouveau tableau. C’est le but de la fonction de rappel, donc nous l’utilisons pour ajouter conditionnellement chaque élément. Si la valeur retournée est fausse, pousser l’élément sur le tableau de retour.

const myCustomFilterFunction = function ( callback ) {
    const newArray = [];

    for (let i = 0; i < this.length; i++) {
        if(callback(this[i]){
            newArray.push(this[i]);
        }

    }

    return newArray;

}

Et c’est terminé pour la méthode Filter. Plutot simple n’est ce pas ?

La fonction de tableau Sort

Sort retourne un tableau trié à partir du tableau d’origine.

Recommençons par la fonction de tri avec une boucle for.

const myCustomSortFunction = function ( callback ) {
    const newArray = [];

    for (let i = 0; i < this.length; i++) {
        console.log(this[i]);
    }
}
Array.prototype.filter = myCustomMapFunction;

Maintenant, les choses commencent à changer un peu. Nous allons utiliser l’algorithme de tri Bubble Sort. Voici la stratégie.

  • répéter l’itération à travers les éléments d’un tableau
  • comparer les termes adjacents et échanger s’ils ne sont pas en ordre
  • après itération n^2 fois, le tableau est trié

Je ne me concentre pas sur la façon la plus efficace de trier, juste la plus facile pour cette démo.

Avec Bubble Sort, vous devez itérer le tableau une fois pour chaque élément du tableau. Cela nécessite une boucle imbriquée où la boucle intérieure itère en s’arrêtant un élément avant l’élément final :

const myCustomSortFunction = function ( callback ) {
    const newArray = [];

    for (let i = 0; i < newArray.length; i++) {
        for(let j =0; j < newArray.length -1; j++){ 
        }
    }
}

Nous ne voulons pas non plus modifier le tableau original. Pour éviter cela, nous pouvons créer une copie du tableau original dans le nouveau tableau à l’aide de l’opérateur Spread.

Comme le fait remarquer dwilahar dans son commentaire, à la différence des autres méthodes la fonction sort n’est pas immutable – c’est à dire qu’elle modifie le tableau original passé en paramètre (tout en renvoyant aussi le tableau trié). Pour être vraiment raccord avec la méthode initiale nous ne sommes donc pas obligé de créer une copie du tableau pour cette méthode.

const myCustomSortFunction = function (callback) {
    const newArray = [...this];

    for (let i = 0; i < newArray.length; i++) {
        for (let j = 0; j < newArray.length -1; j++) { 
        }
    }
}

La fonction de rappel prend deux paramètres, l’élément courant et l’élément suivant, et retourne s’ils sont en ordre ou non. Dans notre cas, si la fonction de rappel renvoie un nombre supérieur à zéro, nous voulons permuter les deux éléments.

const myCustomSortFunction = function (callback) {
    const newArray = [...this];

    for (let i = 0; i < newArray.length; i++) {
        for (let j = 0; j < newArray.length -1; j++) {             
            if (callback(newArray[j], newArray[j+1]) > 0) {
                // swap the elements
            }
        }
    }
}

Pour échanger les éléments, on en fait une copie, on remplace le premier, puis on remplace le second par la copie. Lorsque nous avons terminé, nous retournons le tableau nouvellement trié.

Array.prototype.sort = function (callback) {
  const newArray = [...this]; 

  for (let i =0; i < newArray.length; i++){
    for (let j =0; j < newArray.length -1; j++){         
        if (callback(newArray[j], newArray[j+1]) > 0 ){
            const temp = retVal[j+1];
            retVal[j+1] = retVal[j];
            retVal[j] = temp;
        }
    } 
  }
  //array is sorted
  return newArray;
}

La fonction javascript Reduce

Reduce itére à travers chaque élément et retourne une valeur unique

Reduce ne renvoie pas un nouveau tableau comme ces autres fonctions. Il “réduit” en fait les éléments d’un tableau à une valeur finale, un nombre, une chaîne, un objet, etc. L’exemple le plus simple d’utilisation de reduce est de faire la somme tous les éléments d’un tableau de nombres. Commençons par écraser la fonction comme nous l’avons fait précédemment.

const myCustomReduceFunction = ( callback ) => {
    console.log("My Custom Reduce Function!");
}
Array.prototype.reduce = myCustomReduceFunction;

const arr = [1,2,3];

arr.reduce();

Pour que Reduce renvoie une valeur finale, il faut une valeur de départ pour travailler avec. La fonction de rappel que l’utilisateur transmet déterminera comment mettre à jour cet “accumulateur” en fonction de chaque élément du tableau et le renvoyer à la fin. La fonction de rappel doit renvoyer l’accumulateur mis à jour.

Nous pouvons ajouter notre boucle for maintenant, et faire un appel à la fonction de rappel. La valeur de retour devient le nouvel accumulateur. Une fois la boucle terminée, nous retournons l’accumulateur.

const myCustomReduceFunction = function ( callback, accumulator ) {

    for (let i = 0; i < this.length; i++) {
        accumulator = callback(accumulator, this[i], index);
    }
    return accumulator;
}

Conclusion

Je crois beaucoup à la compréhension du fonctionnement des choses en coulisses, et ce niveau de compréhension est important pour apprendre un nouveau langage, un nouveau cadre, etc. Si vous prenez le temps de creuser et d’apprendre vraiment comment les choses fonctionnent, vous serez beaucoup plus à l’aise avec !

Comme toujours si vous avez aimé cet article n’hésitez pas à le partager ou à me faire des retours en commentaire 😉


siddhy

Développeur web full stack depuis une 15aine d'année dans une agence web du sud de la France et Geek depuis toujours, l'apprentissage et le partage font parti intégrante de ma philosophie au même titre que l'évolution personnelle et la sagesse bouddhiste.

4 commentaires

Purexo · 9 juillet 2019 à 20 h 29 min

Bonjour, aucune des déclaration de fonction n’est valide, c’est un espèce de mix entre fonction fléché et fonction anonyme.

A savoir que dans une méthode fléché, this ne peut être bindé et fait appel au this du scope parent.

La syntaxe à employé ici est :
const myCustomMapMethod = function (callback) {
//code
}
Mais est à préférer :
function myCustomMapMethod(callback) {
// CODE
}
Car au moins cette fonction est nommé, et si celle ci throw une erreur on s’y retrouvera bien plus facilement dans la stackstrace.

De manière générale, il est recommandé de nommer ces fonctions pour cette même raison.

    siddhy · 10 juillet 2019 à 8 h 19 min

    Bien vu ! Les “=>” ont disparu à l’enregistrement.. et c’est exact pour This : A l’inverse d’ES5 dans les fonctions fléchées ES6 ne lient rien à this et celui ci fait bien référence au scope parent

    c’est ce qu’il arrive quand on ne teste pas son code après l’avoir écrit 🙂 Merci pour le commentaire ! Je corrige ça dans la journée !

dwilahar · 11 juillet 2019 à 19 h 27 min

Bonjour,

si je ne me trompe pas, la fonction sort est différent de map, reduce et filter dans le sens où elle n’est pas “immutable”.
On peut faire array1.sort() sans devoir assigner le résultat dans une variable contrairement aux autres méthodes.
La phrase “Nous ne voulons pas non plus modifier le tableau original” n’est donc pas correcte (si l’on se base purement sur le fonctionnement de la méthode sort js), et le tri devrais se faire directement sur le tableau d’origine.

    siddhy · 12 juillet 2019 à 14 h 23 min

    Bonjour dwilahar, En effet tu as raison ! J’ai ajouté une mention dans l’article pour faire part de ta remarque. Merci pour ton commentaire 🙂

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *