Défi
Émilie possède une collection de livres qu'elle souhaite vendre à un libraire en janvier. Elle dispose du prix d'achat de chacun des livres ainsi que d'une estimation du prix de vente sous la forme d'un tableau :
Titre livre | Prix d'achat (en €) | Prix de vente estimé (en €) |
Les Fleurs du Mal | 7.00 | 7.00 |
La Guerre des Intelligences | 20.90 | 1.23 |
Inferno | 9.99 | 5.30 |
… | … | … |
Question
Elle a réalisé un programme en JavaScript dont la logique amène à l'état suivant :
const bookListJanuaryEstimations =
[
['Les Fleurs du Mal', 7.00, 7.00],
['La Guerre des Intelligences', 20.90, 1.23],
['Inferno', 9.99, 5.30]
]
let totalCash = 0
for (const book of bookListJanuaryEstimations) {
totalCash = totalCash + book[2]
}
console.log('Estimation de la vente en Janvier:', totalCash.toFixed(2), '€')
Combien d'argent peut-elle espérer gagner en Janvier avec la présente liste de livres ?
Solution
On exécute le programme et on obtient :
Estimation de la vente en Janvier: 13.53 €
Question
Afin de rendre la logique de calcul plus générale, Émilie décide de modifier le programme pour réaliser l'estimation de ses gains dans une fonction dédiée :
const bookListJanuaryEstimations =
[
['Les Fleurs du Mal', 7.00, 7.00],
['La Guerre des Intelligences', 20.90, 1.23],
['Inferno', 9.99, 5.30]
]
function estimateCashOnSell(totalCash, bookList) {
for (const book of bookList) {
totalCash = totalCash + book[2]
}
}
let totalCash = 0
estimateCashOnSell(totalCash, bookListJanuaryEstimations)
console.log('Estimation de la vente en Janvier:', totalCash.toFixed(2), '€')
Néanmoins elle pense avoir réalisé une erreur. Quel est le résultat retourné par le programme ?
Pourquoi obtient-on ce résultat ?
Proposer une correction à apporter au programme pour corriger ce problème et vérifier qu'on obtient le même résultat que précédemment.
Solution
On obtient :
Estimation de la vente en Janvier: 0.00 €
On obtient ce résultat car totalCash
est passé par valeur : les ajouts qui sont réalisés n'influencent pas la valeur de la variable totalCash
dans l'étendue globale.
Pour corriger ce problème, on peut corriger la fonction pour simplement retourner le montant total estimé de la vente et réaliser la somme avec totalCash
ainsi :
const bookListJanuaryEstimations =
[
['Les Fleurs du Mal', 7.00, 7.00],
['La Guerre des Intelligences', 20.90, 1.23],
['Inferno', 9.99, 5.30]
]
function estimateCashOnSell(bookList) {
let amountEstimate = 0
for (const book of bookList) {
amountEstimate = amountEstimate + book[2]
}
return amountEstimate
}
let totalCash = 0
totalCash = estimateCashOnSell(bookListJanuaryEstimations)
console.log('Estimation de la vente en Janvier:', totalCash.toFixed(2), '€')
On obtient alors le résultat attendu, à savoir :
Estimation de la vente en Janvier: 13.53 €
Question
Émilie dispose maintenant d'estimation de la vente de ces livres pour le mois de février.
Titre livre | Prix d'achat (en €) | Prix de vente estimé (en €) |
Les Fleurs du Mal | 7.00 | 8.23 |
La Guerre des Intelligences | 20.90 | 0.52 |
Inferno | 9.99 | 5.30 |
… | … | … |
Puisque peu de données changent, elle modifie son programme à la marge pour calculer l'estimation de ces gains sur ce nouveau mois ainsi :
const bookListJanuaryEstimations =
[
['Les Fleurs du Mal', 7.00, 7.00],
['La Guerre des Intelligences', 20.90, 1.23],
['Inferno', 9.99, 5.30]
]
bookListFebruaryEstimations = bookListJanuaryEstimations
bookListFebruaryEstimations[0][2] = 8.23
bookListFebruaryEstimations[1][2] = 0.52
function estimateCashOnSell(bookList) {
let amountEstimate = 0
for (const book of bookList) {
amountEstimate = amountEstimate + book[2]
}
return amountEstimate
}
const totalCashJanuary = estimateCashOnSell(bookListJanuaryEstimations)
console.log('Estimation de la vente en Janvier:', totalCashJanuary.toFixed(2), '€')
const totalCashFebruary = estimateCashOnSell(bookListFebruaryEstimations)
console.log('Estimation de la vente en Février:', totalCashFebruary.toFixed(2), '€')
Néanmoins, elle trouve des résultats différents pour le mois de Janvier.
Quel est le résultat de l'exécution de ce programme ?
Pourquoi obtient-on un résultat différent sur le mois de Janvier comparé à précédemment ?
Solution
Le résultat de l'exécution de ce programme est :
Estimation de la vente en Janvier: 14.05 €
Estimation de la vente en Février: 14.05 €
On obtient un résultat différent pour janvier car on a en réalité partagé une valeur de type composé (le tableau) entre les deux variables bookListJanuaryEstimations
et bookListFebruaryEstimations
. Ainsi les modifications faites via bookListFebruaryEstimations
sont rendues visibles à partir de bookListJanuaryEstimations
, d'où un résultat identique pour les deux mois et qui se base sur les prix estimés pour Février.
Question
En relisant son code, elle s'est rendu compte qu'il s'agissait d'un problème de copie de tableaux. Elle modifie donc son code ainsi pour réaliser une copie avec la méthode Object.assign
.
const bookListJanuaryEstimations =
[
['Les Fleurs du Mal', 7.00, 7.00],
['La Guerre des Intelligences', 20.90, 1.23],
['Inferno', 9.99, 5.30]
]
bookListFebruaryEstimations = Object.assign([], bookListJanuaryEstimations)
bookListFebruaryEstimations[0][2] = 8.23
bookListFebruaryEstimations[1][2] = 0.52
function estimateCashOnSell(bookList) {
let amountEstimate = 0
for (const book of bookList) {
amountEstimate = amountEstimate + book[2]
}
return amountEstimate
}
const totalCashJanuary = estimateCashOnSell(bookListJanuaryEstimations)
console.log('Estimation de la vente en Janvier:', totalCashJanuary.toFixed(2), '€')
const totalCashFebruary = estimateCashOnSell(bookListFebruaryEstimations)
console.log('Estimation de la vente en Février:', totalCashFebruary.toFixed(2), '€')
Le résultat persiste-t-il ?
Pourquoi ? S'il persiste, comment peut-on résoudre ce problème ? Modifier le code en conséquence.
Indice
On pourra utiliser la fonction de copie récursive suivante :
const deepCopy = (items) => items.map(item => Array.isArray(item) ? deepCopy(item) : item)
Solution
Le résultat persiste, on obtient toujours :
Estimation de la vente en Janvier: 14.05 €
Estimation de la vente en Février: 14.05 €
Solution
La méthode Object.assign
ne réalise qu'une copie superficielle du tableau : ainsi, les valeurs contenues dans les tableaux imbriqués ne sont pas recopiées et sont partagées entre les deux variables, et on rencontre le même problème que précédemment. Pour résoudre ce problème, c'est-à-dire pour recopier toutes les valeurs, il faut utiliser une copie récursive.
const deepCopy = (items) => items.map(item => Array.isArray(item) ? deepCopy(item) : item)
const bookListJanuaryEstimations =
[
['Les Fleurs du Mal', 7.00, 7.00],
['La Guerre des Intelligences', 20.90, 1.23],
['Inferno', 9.99, 5.30]
]
bookListFebruaryEstimations = deepCopy(bookListJanuaryEstimations)
bookListFebruaryEstimations[0][2] = 8.23
bookListFebruaryEstimations[1][2] = 0.52
function estimateCashOnSell(bookList) {
let amountEstimate = 0
for (const book of bookList) {
amountEstimate = amountEstimate + book[2]
}
return amountEstimate
}
const totalCashJanuary = estimateCashOnSell(bookListJanuaryEstimations)
console.log('Estimation de la vente en Janvier:', totalCashJanuary.toFixed(2), '€')
const totalCashFebruary = estimateCashOnSell(bookListFebruaryEstimations)
console.log('Estimation de la vente en Février:', totalCashFebruary.toFixed(2), '€')
On obtient bien le résultat souhaité :
Estimation de la vente en Janvier: 13.53 €
Estimation de la vente en Février: 14.05 €