let highlightProducts = (products, index = 0) => {
if(index >= products.length) {
return;
}
product = products[index];
if(product.name.indexOf('mountain') !== -1) {
products[index].highlighted = true;
} else if(product.stock > 100 && product.price < 5) {
products[index].highlighted = true;
} else if(product.category == 'outdoors' && product.price < 35 && product.price > 20) {
products[index].highlighted = true;
}
highlightProducts(products, index+1);
}
Personally, I think this exercise is completely fruitless except to teach recursion. products.forEach((p) =>
p.highlighted = (
/mountain/.test(p.name)
|| (p.stock > 100 && p.price < 5)
|| (p.category == 'outdoors' && 20 < p.price && p.price < 35)))
And if one wants the (implicitly hidden) behaviour that highlighted products stay highlighted forever, just add the condition p.highlighted to the disjunction above.;-D
const highlightProducts = ([product, ...productsToProcess], processedProducts = []) => {
if(productsToProcess.length === 0) {
return processedProducts;
}
processedProducts.push({
...product,
highlighted: product.name.indexOf('mountain') !== -1
|| product.stock > 100 && product.price < 5
|| product.category == 'outdoors' && product.price < 35 && product.price > 20
})
return highlightProducts(productsToProcess, processedProducts);
}
or in shorter: const highlightProducts = ([product, ...productsToProcess], processedProducts = []) =>
productsToProcess.length === 0
? processedProducts
: highlightProducts(productsToProcess, [
...processedProducts,
{
...product,
highlighted: product.name.indexOf('mountain') !== -1
|| product.stock > 100 && product.price < 5
|| product.category == 'outdoors' && product.price < 35 && product.price > 20
}
])But I think there's a big difference between a language that lets you expect that iteration b will happen after iteration a, vs a language that merely gives you guarantee the result is derived from application of the function onto the necessary inputs.
The latter can be correctly parallelised, but the former can only ever be executed in serial. `map f [1,2,3]` (in Haskell) can be solved in parallel or in serial. `[1,2,3].map(f)` (in modern JS) must be executed in serial, since f might be the result of `() => { var j = 0; return (i) => { j += i; return j }}`.
Which I'd also argue is a good thing. Using the least powerful construct available both communicates to future readers of the code, and allows higher level optimization (eg, `map` is trivially parallelizable, an arbitrary loop is not)
But honestly, I hate the misleading title of this post, because it completely misdirects what the post is about, which is just breaking logic up into a functions. Typically, you'd teach this by explaining the concept of functions, rather than focusing on loops, which is completely irrelevant to the proper use of functions.