Introduction : pourquoi cette question a rassemblé des milliers de vues sur Stack Overflow
\n\nQuiconque a déjà écrit en JavaScript a rencontré les tableaux. Ils sont partout : listes de produits, files d'attente de tâches, historique des actions utilisateur. Et tôt ou tard, la question se pose : « Comment ajouter un élément au début d'un tableau en JavaScript ? » Sur Stack Overflow, cette question a accumulé des centaines de milliers de vues et des dizaines de réponses. Pourquoi ? Parce que derrière une apparente simplicité se cache tout un ensemble de connaissances : de la performance au fonctionnement interne du moteur.
\n\nDans cet article, nous ne nous contenterons pas de montrer unshift(). Nous allons regarder « sous le capot » : comment le moteur V8 gère l'insertion au début, pourquoi unshift peut être plus lent que push, et quelles alternatives existent pour différents scénarios. C'est parti !
Méthode de base : la méthode unshift()
\n\nLa manière la plus évidente et la plus courante est d'utiliser la méthode intégrée unshift(). Elle ajoute un ou plusieurs éléments au début du tableau et retourne la nouvelle longueur du tableau.
let fruits = ['banane', 'orange'];\nlet newLength = fruits.unshift('pomme');\nconsole.log(fruits); // ['pomme', 'banane', 'orange']\nconsole.log(newLength); // 3\n\nOn peut ajouter plusieurs éléments à la fois :
\n\nlet numbers = [3, 4, 5];\nnumbers.unshift(1, 2);\nconsole.log(numbers); // [1, 2, 3, 4, 5]\n\nOn pourrait s'arrêter là. Mais examinons ce qui se passe à l'intérieur lorsque nous appelons unshift().
Comment fonctionne unshift() sous le capot : un regard sur V8
\n\nUn tableau en JavaScript n'est pas simplement un bloc de mémoire contigu, comme en C. Dans les moteurs modernes (V8 dans Chrome/Node.js, SpiderMonkey dans Firefox), les tableaux peuvent être implémentés de deux manières :
\n\n- \n
- Fast elements (éléments rapides) — un tampon contigu, comme en style C. Optimaux pour la lecture et l'écriture par index. \n
- Dictionary elements (éléments dictionnaire) — une table de hachage. Utilisée lorsque le tableau devient « troué » (sauts d'index) ou trop grand. \n
Lorsque vous appelez unshift() sur un tableau rapide, le moteur fait ceci :
- \n
- Alloue une nouvelle mémoire (ou décale la mémoire existante) du nombre d'éléments à ajouter. \n
- Décale tous les éléments existants vers la droite de
npositions. \n - Écrit les nouveaux éléments dans les cellules libérées au début. \n
Pourquoi unshift est-il plus lent que push ?
\n\nLa méthode push() ajoute un élément à la fin — elle n'a rien à décaler. unshift(), quant à elle, réécrit les index pour chaque élément existant. Si le tableau contient 1000 éléments, unshift doit décaler les 1000. push se contente d'ajouter à la fin.
Dans V8, il existe une optimisation : si le tableau est vide ou presque vide, le décalage est quasiment gratuit. Mais pour les grands tableaux, la différence de performance peut être décuplée. Surtout si vous faites unshift dans une boucle.
// Mauvais : O(n²) à cause du décalage constant\nlet arr = [];\nfor (let i = 0; i < 10000; i++) {\n arr.unshift(i);\n}\n\n// Bon : O(n) — on ajoute à la fin, puis on inverse\nlet arr2 = [];\nfor (let i = 0; i < 10000; i++) {\n arr2.push(i);\n}\narr2.reverse();\n\nAlternative : l'opérateur spread (ES6+)
\n\nUne manière moderne et élégante consiste à utiliser l'opérateur spread ... pour créer un nouveau tableau :
let oldArray = [2, 3, 4];\nlet newArray = [1, ...oldArray];\nconsole.log(newArray); // [1, 2, 3, 4]\n\nCette approche ne mute pas le tableau d'origine, ce qui est souvent pratique en programmation fonctionnelle (React, Redux). Mais rappelez-vous : un nouveau tableau est créé, et les anciens éléments sont copiés. Pour les tableaux géants, cela peut être coûteux en mémoire.
\n\nAjout de plusieurs éléments au début
\n\nlet base =