Fusionner des tableaux est l'une des operations les plus courantes en developpement JavaScript. Que vous combiniez
des donnees provenant de plusieurs sources, que vous construisiez des listes dynamiques ou que vous geriez un state
dans vos applications, comprendre les differentes facons de fusionner des tableaux est crucial. Ce guide complet
explore 6 methodes differentes pour fusionner des tableaux en JavaScript, de la methode traditionnelle concat() aux approches
modernes comme l'operateur spread, avec des considerations de performance et des bonnes pratiques pour chaque
methode.
Comprendre la fusion de tableaux
La fusion de tableaux en JavaScript consiste a combiner deux ou plusieurs tableaux en un seul tableau. La distinction cle se fait entre les methodes qui creent un nouveau tableau (immutables) et celles qui modifient le tableau existant (mutables). Comprendre cette difference est essentiel pour ecrire du code previsible et maintenable.
Avant de voir les methodes, etablissons quelques scenarios courants ou la fusion de tableaux est essentielle :
- Combiner des donnees provenant de plusieurs reponses d'API
- Construire des listes dynamiques dans des applications React ou Vue
- Gerer des mises a jour de state dans Redux ou des bibliotheques similaires
- Traiter et agreger des donnees provenant de differentes sources
- Creer des resultats de recherche complets a partir de plusieurs datasets
Methode 1 : Array.concat() - l'approche traditionnelle
La methode concat() est
l'approche la plus traditionnelle et la plus largement supportee pour fusionner des tableaux. Elle cree un nouveau
tableau contenant les elements du tableau d'origine suivis des elements des tableaux (ou valeurs) ajoutes.
Utilisation de base
const fruits = ['🍎', '🍌'];
const vegetables = ['🥕', '🥬'];
const combined = fruits.concat(vegetables);
console.log(combined); // ['🍎', '🍌', '🥕', '🥬']
console.log(fruits); // ['🍎', '🍌'] - original array unchanged
console.log(vegetables); // ['🥕', '🥬'] - original array unchanged
Fusionner plusieurs tableaux
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
// Method 1: Chaining concat calls
const result1 = array1.concat(array2).concat(array3);
// Method 2: Passing multiple arguments
const result2 = array1.concat(array2, array3);
// Method 3: Using empty array as base
const result3 = [].concat(array1, array2, array3);
console.log(result1); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(result2); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(result3); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Gerer des valeurs qui ne sont pas des tableaux
L'un des avantages cles de concat()
est sa capacite a gerer proprement des valeurs qui ne sont pas des tableaux :
const numbers = [1, 2, 3];
const string = 'hello';
const number = 42;
const result = numbers.concat(string, number);
console.log(result); // [1, 2, 3, 'hello', 42]
Avantages :
- Excellent support navigateur (fonctionne dans tous les navigateurs)
- Gere proprement les valeurs non-tableau
- Cree un nouveau tableau (immuable)
- Syntaxe claire et lisible
Inconvenients :
- Peut etre verbeux quand on fusionne beaucoup de tableaux
- Un peu plus lent que certaines alternatives modernes
Methode 2 : operateur spread (...) - l'approche moderne
L'operateur spread, introduit en ES6, fournit une facon concise et elegante de fusionner des tableaux. Il etend un iterable (comme un tableau) en elements individuels.
Utilisation de base
const fruits = ['🍎', '🍌'];
const vegetables = ['🥕', '🥬'];
const combined = [...fruits, ...vegetables];
console.log(combined); // ['🍎', '🍌', '🥕', '🥬']
console.log(fruits); // ['🍎', '🍌'] - original array unchanged
console.log(vegetables); // ['🥕', '🥬'] - original array unchanged
Fusionner plusieurs tableaux
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
const combined = [...array1, ...array2, ...array3];
console.log(combined); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Ajouter des elements individuels
const numbers = [1, 2, 3];
const moreNumbers = [...numbers, 4, 5, 6];
console.log(moreNumbers); // [1, 2, 3, 4, 5, 6]
// Adding elements at the beginning
const evenMoreNumbers = [0, ...numbers, 4];
console.log(evenMoreNumbers); // [0, 1, 2, 3, 4]
Limitation importante : valeurs qui ne sont pas des tableaux
Contrairement a concat(),
l'operateur spread exige que toutes les valeurs soient iterables :
const numbers = [1, 2, 3];
const string = 'hello';
// This works - string is iterable
const result1 = [...numbers, ...string];
console.log(result1); // [1, 2, 3, 'h', 'e', 'l', 'l', 'o']
// This will throw an error
const number = 42;
// const result2 = [...numbers, ...number]; // TypeError: number is not iterable
Avantages :
- Syntaxe concise et lisible
- Excellentes performances
- Cree un nouveau tableau (immuable)
- Flexible pour ajouter des elements individuels
Inconvenients :
- Necessite le support ES6+
- Toutes les valeurs doivent etre iterables
- Peut etre source de confusion avec des valeurs non-tableau
Methode 3 : Array.push() avec spread - l'approche mutable
La methode push()
modifie le tableau d'origine en ajoutant des elements a la fin. Combinee a l'operateur spread, elle peut fusionner
des tableaux efficacement.
Utilisation de base
const fruits = ['🍎', '🍌'];
const vegetables = ['🥕', '🥬'];
fruits.push(...vegetables);
console.log(fruits); // ['🍎', '🍌', '🥕', '🥬'] - original array modified
console.log(vegetables); // ['🥕', '🥬'] - unchanged
Fusionner plusieurs tableaux
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const array3 = [7, 8, 9];
array1.push(...array2, ...array3);
console.log(array1); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Considerations de performance
push() avec spread peut
etre tres efficace pour les grands tableaux car il ne cree pas de nouveau tableau :
// Efficient for large arrays
const largeArray = new Array(1000000).fill(0);
const additionalData = [1, 2, 3, 4, 5];
// This modifies the original array without creating a new one
largeArray.push(...additionalData);
Avantages :
- Tres efficace pour les grands tableaux
- Pas de creation de nouveau tableau
- Syntaxe simple
- Bonnes performances
Inconvenients :
- Modifie le tableau d'origine (mutable)
- Peut provoquer des effets de bord inattendus
- Pas adapte aux patterns de programmation fonctionnelle
Methode 4 : Array.from() avec concat() - l'approche fonctionnelle
Array.from() combine a
concat() fournit une
approche de programmation fonctionnelle pour fusionner des tableaux.
Utilisation de base
const arrays = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
const merged = Array.from(arrays).reduce((acc, curr) => acc.concat(curr), []);
console.log(merged); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Utiliser Array.from() avec spread
const arrays = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
const merged = Array.from(arrays).reduce((acc, curr) => [...acc, ...curr], []);
console.log(merged); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Avantages :
- Approche de programmation fonctionnelle
- Fonctionne bien avec un tableau de tableaux
- Cree un nouveau tableau (immuable)
Inconvenients :
- Syntaxe plus complexe
- Peut etre plus lent pour les cas simples
- Moins lisible que d'autres methodes
Methode 5 : Array.flat() - l'approche flattening
Array.flat() est parfait
quand vous avez un tableau de tableaux et que vous voulez l'aplatir en un seul tableau.
Utilisation de base
const arrays = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
const flattened = arrays.flat();
console.log(flattened); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
Gerer des tableaux imbriques
const nestedArrays = [
[1, 2, [3, 4]],
[5, 6, [7, 8]],
[9, 10]
];
// Flatten one level
const oneLevel = nestedArrays.flat();
console.log(oneLevel); // [1, 2, [3, 4], 5, 6, [7, 8], 9, 10]
// Flatten completely
const completelyFlat = nestedArrays.flat(Infinity);
console.log(completelyFlat); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Avantages :
- Parfait pour un tableau de tableaux
- Gere les structures imbriquees
- Simple et lisible
- Cree un nouveau tableau (immuable)
Inconvenients :
- Necessite le support ES2019+
- Ne fonctionne qu'avec un tableau de tableaux
- Peut trop aplatir si on ne fait pas attention
Methode 6 : fonction utilitaire sur mesure - l'approche flexible
Parfois, vous avez besoin d'une solution sur mesure qui gere des exigences specifiques ou des cas limites. Creer une fonction utilitaire vous donne un controle total sur le processus de fusion.
Fonction utilitaire de base
function mergeArrays(...arrays) {
return arrays.reduce((acc, curr) => {
if (Array.isArray(curr)) {
return acc.concat(curr);
} else {
return acc.concat([curr]);
}
}, []);
}
const result = mergeArrays([1, 2], [3, 4], 5, [6, 7]);
console.log(result); // [1, 2, 3, 4, 5, 6, 7]
Utilitaire avance avec options
function mergeArrays(options = {}) {
const {
arrays = [],
unique = false,
filter = null,
sort = false
} = options;
let result = arrays.reduce((acc, curr) => {
if (Array.isArray(curr)) {
return acc.concat(curr);
} else {
return acc.concat([curr]);
}
}, []);
if (filter) {
result = result.filter(filter);
}
if (unique) {
result = [...new Set(result)];
}
if (sort) {
result = result.sort();
}
return result;
}
// Usage examples
const arrays = [[1, 2, 3], [2, 3, 4], [3, 4, 5]];
// Basic merge
const basic = mergeArrays({ arrays });
console.log(basic); // [1, 2, 3, 2, 3, 4, 3, 4, 5]
// Merge with unique values
const unique = mergeArrays({ arrays, unique: true });
console.log(unique); // [1, 2, 3, 4, 5]
// Merge with filtering
const filtered = mergeArrays({
arrays,
filter: x => x > 2
});
console.log(filtered); // [3, 3, 4, 3, 4, 5]
Avantages :
- Controle total sur le processus
- Peut gerer des exigences complexes
- Reutilisable entre projets
- Peut inclure de la logique additionnelle
Inconvenients :
- Necessite plus de code
- Il faut maintenir la fonction
- Peut etre overkill pour des cas simples
Comparaison de performances
Comprendre les caracteristiques de performance de chaque methode est essentiel pour choisir la bonne approche, surtout quand on travaille avec de grands datasets.
Resultats de tests de performance
// Performance test function
function performanceTest(method, arrays, iterations = 1000) {
const start = performance.now();
for (let i = 0; i < iterations; i++) {
method(arrays);
}
const end = performance.now();
return end - start;
}
// Test data
const largeArray1 = new Array(10000).fill(0).map((_, i) => i);
const largeArray2 = new Array(10000).fill(0).map((_, i) => i + 10000);
// Test methods
const methods = {
concat: (arrays) => arrays[0].concat(arrays[1]),
spread: (arrays) => [...arrays[0], ...arrays[1]],
push: (arrays) => {
const result = [...arrays[0]];
result.push(...arrays[1]);
return result;
},
flat: (arrays) => [arrays[0], arrays[1]].flat()
};
// Run tests
const testArrays = [largeArray1, largeArray2];
const results = {};
for (const [name, method] of Object.entries(methods)) {
results[name] = performanceTest(method, testArrays);
}
console.log('Performance Results (ms):', results);
Classement des performances (resultats typiques)
- push() avec spread : le plus rapide pour les grands tableaux (pas de creation de nouveau tableau)
- concat() : bonnes performances, coherentes selon les navigateurs
- Operateur spread : rapide mais peut etre plus lent avec des tableaux tres grands
- flat() : pratique pour un tableau de tableaux, plus lent pour une fusion simple
- Fonctions sur mesure : la performance depend de l'implementation
Problemes courants et depannage
Probleme 1 : operateur spread avec des valeurs non iterables
Probleme : tenter de spread des valeurs non iterables provoque des erreurs.
const numbers = [1, 2, 3];
const notAnArray = 42;
// This will throw an error
// const result = [...numbers, ...notAnArray]; // TypeError: 42 is not iterable
Solution : verifiez si la valeur est iterable ou utilisez concat() a la place.
const numbers = [1, 2, 3];
const notAnArray = 42;
// Safe approach with concat
const result = numbers.concat(notAnArray);
console.log(result); // [1, 2, 3, 42]
// Or check if iterable first
const safeResult = [...numbers, ...(Array.isArray(notAnArray) ? notAnArray : [notAnArray])];
console.log(safeResult); // [1, 2, 3, 42]
Probleme 2 : mutation inattendue avec push()
Probleme : utiliser push() modifie le tableau d'origine, ce qui cause des effets de bord inattendus.
const originalArray = [1, 2, 3];
const additionalData = [4, 5, 6];
originalArray.push(...additionalData);
console.log(originalArray); // [1, 2, 3, 4, 5, 6] - modified!
// This can cause bugs if you expected originalArray to remain unchanged
Solution : creez d'abord une copie ou utilisez des methodes immuables.
const originalArray = [1, 2, 3];
const additionalData = [4, 5, 6];
// Solution 1: Create a copy first
const result1 = [...originalArray];
result1.push(...additionalData);
// Solution 2: Use immutable methods
const result2 = [...originalArray, ...additionalData];
console.log(originalArray); // [1, 2, 3] - unchanged
console.log(result1); // [1, 2, 3, 4, 5, 6]
console.log(result2); // [1, 2, 3, 4, 5, 6]
Probleme 3 : problemes de memoire avec de grands tableaux
Probleme : creer de nouveaux tableaux avec de gros datasets peut provoquer des problemes de memoire.
// This can cause memory issues with very large arrays
const hugeArray1 = new Array(1000000).fill(0);
const hugeArray2 = new Array(1000000).fill(1);
// Creates a new array with 2 million elements
const merged = [...hugeArray1, ...hugeArray2];
Solution : utilisez push() pour les grands tableaux ou traitez par chunks.
const hugeArray1 = new Array(1000000).fill(0);
const hugeArray2 = new Array(1000000).fill(1);
// More memory efficient
hugeArray1.push(...hugeArray2);
// Or process in chunks for very large datasets
function mergeInChunks(array1, array2, chunkSize = 10000) {
for (let i = 0; i < array2.length; i += chunkSize) {
const chunk = array2.slice(i, i + chunkSize);
array1.push(...chunk);
}
return array1;
}
Exemples du monde reel
Exemple 1 : fusionner des reponses d'API
// Simulating API responses
async function fetchUserData() {
const [users, posts, comments] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json()),
fetch('/api/comments').then(r => r.json())
]);
// Merge all data into a single array
const allData = [...users, ...posts, ...comments];
return allData;
}
Exemple 2 : gestion de state React
// React component with state merging
function TodoList() {
const [todos, setTodos] = useState([]);
const [newTodos, setNewTodos] = useState([]);
const addNewTodos = () => {
// Immutable update using spread operator
setTodos(prevTodos => [...prevTodos, ...newTodos]);
setNewTodos([]);
};
const addSingleTodo = (todo) => {
// Adding single item
setTodos(prevTodos => [...prevTodos, todo]);
};
return (
// Component JSX
);
}
Exemple 3 : pipeline de traitement de donnees
function processData(rawData) {
// Step 1: Merge data from different sources
const mergedData = rawData.reduce((acc, source) => {
return acc.concat(source.data);
}, []);
// Step 2: Filter and transform
const processedData = mergedData
.filter(item => item.active)
.map(item => ({
...item,
processedAt: new Date()
}));
// Step 3: Remove duplicates
const uniqueData = [...new Set(processedData.map(item => item.id))]
.map(id => processedData.find(item => item.id === id));
return uniqueData;
}
Bonnes pratiques et recommandations
Quand utiliser chaque methode
- Utilisez concat() : quand vous voulez un maximum de compatibilite navigateur ou que vous gerez des types de donnees mixtes
- Utilisez l'operateur spread : pour des codebases modernes (ES6+) avec une syntaxe propre et lisible
- Utilisez push() avec spread : quand la performance est critique et que vous pouvez muter le tableau d'origine sans risque
- Utilisez flat() : quand vous avez un tableau de tableaux et que vous voulez les aplatir
- Utilisez des fonctions sur mesure : quand vous avez besoin de logique complexe ou d'exigences specifiques
Regles de performance
- Pour de petits tableaux (< 1000 elements) : utilisez l'operateur spread pour la lisibilite
- Pour de grands tableaux (> 10000 elements) : utilisez push() avec spread pour la performance
- Pour des types de donnees mixtes : utilisez concat() pour la securite
- Pour un tableau de tableaux : utilisez flat() pour la simplicite
Conseils de qualite de code
- Pensez toujours a si vous avez besoin d'un nouveau tableau ou si vous pouvez modifier l'existant
- Utilisez des methodes coherentes dans toute votre codebase
- Ajoutez des commentaires pour les logiques de fusion complexes
- Testez avec des cas limites (tableaux vides, valeurs null, etc.)
- Pensez a utiliser TypeScript pour une meilleure surete de types
Compatibilite navigateur
Comprendre le support navigateur est essentiel pour choisir la bonne methode pour votre projet :
Matrice de support
- concat() : tous les navigateurs (IE5.5+)
- Operateur spread : navigateurs modernes (Chrome 46+, Firefox 16+, Safari 8+)
- push() : tous les navigateurs (IE5.5+)
- flat() : navigateurs modernes (Chrome 69+, Firefox 62+, Safari 12+)
- Array.from() : navigateurs modernes (Chrome 45+, Firefox 32+, Safari 9+)
Polyfills et fallbacks
// Polyfill for flat() if needed
if (!Array.prototype.flat) {
Array.prototype.flat = function(depth = 1) {
return this.reduce((acc, val) => {
if (Array.isArray(val) && depth > 0) {
acc.push(...val.flat(depth - 1));
} else {
acc.push(val);
}
return acc;
}, []);
};
}
// Safe spread operator usage
function safeSpread(...arrays) {
return arrays.reduce((acc, curr) => {
if (Array.isArray(curr)) {
return [...acc, ...curr];
} else {
return [...acc, curr];
}
}, []);
}
Conclusion
Fusionner des tableaux en JavaScript est une operation fondamentale que chaque developpeur devrait maitriser.
Chacune des 6 methodes que nous avons vues a ses points forts et ses cas d'usage. La methode concat() reste l'approche la
plus fiable et la plus largement supportee, tandis que l'operateur spread offre une syntaxe moderne et d'excellentes
performances dans la plupart des cas.
La cle pour choisir la bonne methode est de comprendre vos besoins : devez-vous preserver le tableau d'origine ? Travaillez-vous avec de grands datasets ? Devez-vous gerer des types de donnees mixtes ? En tenant compte de ces facteurs et en suivant les bonnes pratiques de ce guide, vous pouvez ecrire du code efficace et maintenable qui gere correctement la fusion de tableaux.
Gardez en tete que les considerations de performance deviennent plus importantes a mesure que vos donnees grandissent, et testez toujours votre methode avec des tailles de donnees realistes. Que vous construisiez une application web simple ou un systeme complexe de traitement de donnees, la bonne technique de fusion de tableaux vous aidera a ecrire un code JavaScript plus propre et plus efficace.
A mesure que JavaScript evolue, de nouvelles methodes et optimisations apparaitront, mais les principes fondamentaux de manipulation de tableaux restent constants. En maitrisant ces 6 methodes, vous serez pret a gerer n'importe quel defi de fusion de tableaux.