Les bonnes pratiques concernant l'usage des tableau en Javascript est indispensable. Les tableau nous simplifient la vie et rendent
l'usage des boucles presque useless.
Je vais essayer au travers de ce cours de vous montrer un maximum de cas d'usage utiles dans votre quotidien, ne vous inquiétez
pas certains usages seront un peu exotique mais très pratique à utiliser avec des Frameworks.
Différentes manières de créer un tableau
Création d'un tableau
// Création d'un tableau de string
const languages = ['Python', 'Java', 'C', 'C++', 'Javascript', 'PHP']
// Création d'un tableau d'objet
const films = [
{
name: 'Iron Man',
producer: 'Jon Favreau',
releaseDate: 2008,
},
{
name: 'Iron Man 2',
producer: 'Jon Favreau',
releaseDate: 2010,
},
{
name: 'Thor',
producer: 'Kenneth Branagh',
releaseDate: 2011,
}
]
// Création d'un tableau a partir d'une nodeList
let NodeList = document.querySelectorAll('p')
const elements = Array.from(NodeList)
Techniques avancées, voir exotiques
Voila quelques techniques supplémentaires pour créer un tableau, nous verons un peu plutard comment et dans quel cas on pourra s'en servir.
// Créer un tableau de caractères à partir d'une chaine
const string = 'ma chaine'
const array = [...string]// ['m', 'a', ' ', 'c', 'h', 'a', 'i', 'n', 'e']
// Créer un tableau à partir d'un objet
const object = {
name: 'Thor',
producer: 'Kenneth Branagh',
releaseDate: 2011,
}
// tableau avec les valeurs de l'objet
const array = Object.values(object)// ['Thor', 'Kenneth Branagh', 2011]
// tableau avec les clés de l'objet
const array = Object.keys(object)// ['name', 'producer', 'releaseDate']
// tableau avec les paires clés, valeurs de l'objet
const array = Object.entries(object)// [['name', 'Thor'], ['producer', 'Kenneth Branagh'], ['releaseDate', 2011]]
// Créer un tableau de n éléments
const array = [...Array(5).keys()]// [0, 1, 2, 3, 4]
Les méthodes de l'objet Array
Manipulation de base
Il est indispensable de connaitre ces méthodes par cœur.
const languages = ['Python', 'Java', 'C', 'C++', 'Javascript']
// Ajouter un élément à la fin (retourne la nouvelle longueur)
languages.push('PHP')// 6
// Ajouter un élément au début (retourne la nouvelle longueur)
languages.unshift('Ruby')// 7
// Supprimer le dernier élément (retourne l'élément supprimé)
languages.pop()// 'PHP'
// Supprimer le premier élément (retourne l'élément supprimé)
languages.shift()// 'Ruby'
// Retourne la longueur d'un Array
languages.length// 5
// Retourne la fin d'un Array à partir de l'index
languages.slice(2)//['C++', 'Javascript']
Manipulation d'index
Plusieurs méthodes vous permettent d'accéder à un index, d'en rechercher un ou de supprimer un élément par son index.
const colors = ['bleu', 'rouge', 'vert', 'jaune', 'bleu']
// Retourne une section à partir de l'index de départ (1) et l'index de fin (2)
languages.slice(1, 2)//['rouge']
// Retourne l'index du premier élément ou -1
colors.indexOf('bleu')// 0
colors.indexOf('orange')// -1
// Retourne l'index du dernier élément ou -1
colors.lastIndexOf('bleu')// 4
colors.lastIndexOf('orange')// -1
// Retire 1 élément à partir de l'index 0 et retourne l'élément retiré
colors.splice(0, 1)// 'bleu'
// Et si on mix tout on peut retirer un élément précis et le retourné
colors.splice(colors.indexOf('vert'), 1)// 'vert'
Classement
Particulièrement utile quand on manipule de grandes quantités de données, les méthodes de trie sont indispensables.
// Retourne un tableau en inversant les clés
const chiffres = ["un", "deux", "trois"]
chiffres.reverse()// ["trois", "deux", "un"]
// Retourne un tableau trier par ordre alphabétique
const pays = ["Allemagne", "France", "Italie", "Espagne", "Portugal"]
pays.sort()// ['Allemagne', 'Espagne', 'France', 'Italie', 'Portugal']
pays.sort((a, b) => a - b)// ['Allemagne', 'Espagne', 'France', 'Italie', 'Portugal']
// Retourne un tableau trier par ordre alphabétique inversé
pays.sort((a, b) => b - a)// ['Allemagne', 'France', 'Italie', 'Espagne', 'Portugal']
// Trie avec des dates
const dates = ['2020-02-29', '2021-12-17', '2022-01-15']
dates.sort((a, b) => new Date(a) - new Date(b))// ['2020-02-29', '2021-12-17', '2022-01-15']
// Inversé
dates.sort((a, b) => new Date(b) - new Date(a))// ['2022-01-15', '2021-12-17', '2020-02-29']
// Conditionnel (Souvent utilisé dans les data table)
let sort = "ASC"
dates.sort(// ['2020-02-29', '2021-12-17', '2022-01-15']
(a, b) => sort === "ASC" ?
new Date(a) - new Date(b) :
new Date(b) - new Date(a)
)
sort = "DESC"
dates.sort(// ['2022-01-15', '2021-12-17', '2020-02-29']
(a, b) => sort === "ASC" ?
new Date(a) - new Date(b) :
new Date(b) - new Date(a)
)
Recherche
// On va reprendre nos films un peu enrichit
const films = [
{
name: 'Iron Man',
producer: 'Jon Favreau',
releaseDate: 2008,
type: 'MCU',
actors: ['Robert Downey Jr.', 'Gwyneth Paltrow', 'Terrence Howard', 'Jeff Bridges'],
},
{
name: 'Iron Man 2',
producer: 'Jon Favreau',
releaseDate: 2010,
type: 'MCU',
actors: ['Robert Downey Jr.', 'Mickey Rourke', 'Gwyneth Paltrow', 'Scarlett Johansson'],
},
{
name: 'Thor',
producer: 'Kenneth Branagh',
releaseDate: 2011,
type: 'MCU',
actors: ['Chris Hemsworth', 'Natalie Portman', 'Tom Hiddleston', 'Anthony Hopkins'],
}
]
// Retourne le premier élément correspondant au producteur
const producer = "Jon Favreau"
films.find(film => film.producer === producer)// {name: 'Iron Man', producer: 'Jon Favreau', releaseDate: 2008, type: 'MCU', actors: ['Robert Downey Jr.', 'Gwyneth Paltrow', 'Terrence Howard', 'Jeff Bridges']}
// Retourne l'index du premier élément correspondant au producteur
films.findIndex(film => film.producer === producer)// 0
// Retourne true si au moins un élément correspond au producteur
films.some(film => film.producer === producer)// true
// Retourne true si tous les éléments correspondent au MCU
const type = "MCU"
films.every(film => film.type === type)// true
// Un peu de recherche avec filter
films.filter(film => film.producer === producer)// Retourne les éléments correspondant au producteur
const search1 = 'Iron man'
films.filter(// Retourne les films contenant le motif de recherche dans le nom
film => film.name.toLowerCase().includes(search1.toLowerCase())
)
// Recherche de second niveau
const search2 = 'Gwyneth'
films.filter(// Retourne les films contenant le motif dans le nom d'un acteur
film => film.actors.some(actor => actor.toLowerCase().includes(search2.toLowerCase()))
)
// Si je vous ai perdu on le fait au ralenti
films.filter(
film => {// On filtre les résultats de façon conditionnel
return film.actors.some(// On parcours les acteurs à la recherche d'une correspondance
actor => {
const actorLowerCase = actor.toLowerCase()// Acteur en minuscule
const search = search2.toLowerCase()// Motif de recherche en minuscule
return actorLowerCase.includes(search)// On verifie si un acteur contient le motif
}
)
}
)
Opérations avec reduce
Cette méthode permet de réduire tous les éléments d'un tableau à une seule valeur. Particulièrement utiles pour faire des calculs
dans un tableau. Je m'en sers très peu mais c'est toujours bien de savoir qu'elle existe.
// Un nouveau tableau avec des likes
const photos = [
{
name: 'Glace en formation',
likes: 27625854,
},
{
name: 'La baie des singes',
likes: 2597,
},
{
name: 'Table en bois brut dans un magnifique cadre',
likes: 125442,
}
]
// Une méthode simple pour compter les likes de toutes les photos
photos.reduce((likes, photo) => likes + photo.likes, 0)
// Reduce prend en paramètres une callback et une valeur initial au ralenti ça donne
const result = photos.reduce(
(
likes,// Valeur précédente on commencera la première itération avec la valeur initial soit 0
photo// Valeur courante de l'itération
) =>
likes + photo.likes// On additionne la valeur précédente avec la valeur courante de like
,
0// Valeur initial
)
Transformations avec map
Cette méthode permet de créer un nouveau tableau en manipulant les valeurs d'un tableau existant. Certainement la méthode la plus utilisée
par les développeurs React, elle nous permet d'itérer sur tableau et d'en sortir du JSX.
// Reprenons nos films
const films = [
{
name: 'Iron Man',
producer: 'Jon Favreau',
releaseDate: 2008,
},
{
name: 'Iron Man 2',
producer: 'Jon Favreau',
releaseDate: 2010,
},
{
name: 'Thor',
producer: 'Kenneth Branagh',
releaseDate: 2011,
}
]
// Je veux la liste de nom de films séparé par une virgule
films.map(film => film.name).join(', ')// Iron Man, Iron Man 2, Thor
// Je veux ajouter le studio Disney à tous les films
films.map(film => ({...film, studio: 'Disney'}))// Version destructuring
films.map(film => {// Version sans destructuring
film.studio = 'Disney'
return film
})
// Je veux ajouter une année à chaque film
films.map(film => ({...film, releaseDate: film.releaseDate + 1}))// Version destructuring
films.map(film => {// Version sans destructuring
film.releaseDate += 1
return film
})
// Pour sortir un peu des films, je veux générer un tableau avec n nombre aléatoire pour une animation
const arrayRandom = [...Array(5)].map(i => Math.floor(Math.random() * 10))
// Je veux générer des transformations aléatoire pour une animation
const result = [...Array(5)].map(i => ({
transform: `translate(${Math.floor(Math.random() * 1.2 * 100) + "px"}, ${Math.floor(Math.random() * 1.2 * 100) + "px"}) rotate(${Math.floor(Math.random() * 360)}deg)`
}))
Manipulation recursive sur des tableaux en imbriqués
Il arrive souvent quand on travail avec des api d'avoir des données imbriqués les une dans les autres. On appelle cela des nested data.
// Prenons un jeu de données en imbriqué avec des catégories
const categories = [
{ id: 1, name: 'Category 1', selected: false, children: [
{ id: 2, parentId: 1, name: 'Category 1.1', selected: false, children: [
{ id: 3, parentId: 2, name: 'Category 1.1.1', selected: false },
{ id: 4, parentId: 2, name: 'Category 1.1.2', selected: false },
]},
{ id: 5, parentId: 1, name: 'Category 1.2', selected: false, children: [
{ id: 6, parentId: 5, name: 'Category 1.2.1', selected: false },
{ id: 7, parentId: 5, name: 'Category 1.2.2', selected: false },
{ id: 8, parentId: 5, name: 'Category 1.2.3', selected: false },
]},
]},
{ id: 9, name: 'Category 2', selected: false, children: [
{ id: 10, parentId: 9, name: 'Category 2.1', selected: false, children: [
{ id: 11, parentId: 10, name: 'Category 2.1.1', selected: false },
{ id: 12, parentId: 10, name: 'Category 2.1.2', selected: true },
]},
{ id: 13, name: 'Category 2.2', selected: false, children: [
{ id: 14, parentId: 13, name: 'Category 2.2.1', selected: false },
{ id: 15, parentId: 13, name: 'Category 2.2.2', selected: false },
{ id: 16, parentId: 13, name: 'Category 2.2.3', selected: false },
]},
]},
]
// Nous cherchons pour un select quel l'élément de premier niveau à afficher
let open = categories.find(function f(category) {// On cherche
if (category.selected === true) {
return true
} else if (category.children && category.children.length) {
return category.children.find(f)
} else {
return false
}
})
// Nous souhaitons mettre le tableau à plat pour simplifier l'usage
const flatArray = []
categories.forEach(function f(category) {
flatArray.push(category)
if (category.children && category.children.length) category.children.forEach(f, null)
})
// Nous souhaitons mettre le tableau à plat dans un objet ordonné par id
const flatObject = {}
categories.forEach(function f(category) {
flatObject[category.id] = category
if (category.children && category.children.length) category.children.forEach(f, null)
})
Destructuring et spread
Dernier point important de ce cours sur les tableaux, le destructuring et l'opérateur spread
// Prenons un array
const array1 = [1, 2, 3, 4, 5]
// Nous pouvons en faire une copie non liée avec l'opérateur spread
const array2 = [...array1]// [1, 2, 3, 4, 5]
// Nous pouvons égualement ajouter un tableau à la suite d'un autre avec l'opérateur spread
const array3 = [...array1, ...array2]// [1, 2, 3, 4, 5, 1, 2, 3, 4, 5]
// Obtenir un équivalent de push et unshift
array1.unshift(0)// [0, 1, 2, 3, 4, 5]
array1.push(6)// [0, 1, 2, 3, 4, 5, 6]
const array4 = [0, ...array1, 6]// [0, 1, 2, 3, 4, 5, 6]
// Coté le destructuring nous pouvons récupérer une propriété de Array
const { length } = array4// length = 7
// Une partie d'un tableau
const [ key0, key1, key2 ] = array4// key0 = 0, key1 = 1, key2 = 2
// Et bien d'autres choses en mélangeant ces 2 techniques, comme mon helper ucFirst que j'utilise souvent
let string = 'ma chaine'
const [ first, ...rest ] = string// first = 'm', rest = ['a', ' ', 'c', 'h', 'a', 'i', 'n', 'e']
string = first.toLocaleUpperCase() + rest.join('')// 'Ma chaine'
// Sous forme de fonction fléchée ça donne
const usFirst = ([ first, ...rest ]) => first.toLocaleUpperCase() + rest.join('')
Conclusion
Une bonne connaissance de l'objet Array et de ses méthodes est réellement indispensable dans la vie d'un développeur qu'il soit frontend,
node ou fullstack JS. J'ai essayé au travers de ce cours de vous partager les choses les plus importantes mais il n'est pas exhaustif.
il vous restera encore beaucoup de choses à apprendre, mais ces bases auront l'avantage de vous permettre de le faire seul.
Comme d'habitude si vous avez besoin de complément d'information, je reste à votre disposition sur Discord, par mail, ...