I am using forEach() method called from an array in JavaScript. When I write return;
somewhere inside the method which is called for every element in array I return
To quote Mozilla Developer Network:
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool, use a plain loop instead. If you are testing the array elements for a predicate and need a Boolean return value, you can use every() or some() instead. If available, the new methods find() or findIndex() can be used for early termination upon true predicates as well.
Having said that, I believe your solution to have set a flag to return out of the function is the most appropriate and simple.
You could do the following, with Array#find
:
function addToCart(pizza, size)
{
// find the first item where the condition is true,
// or undefined if there is none
var sameSizeItem = Cart.find(function (item) {
return pizzaAndSizeAreTheSame(item, pizza, size);
});
if (sameSizeItem) {
sameSizeItem.quantity++;
updateCart();
return;
}
Cart.push({
pizza: pizza,
size: size,
quantity: 1
});
updateCart();
}
A little more adjustment and you can avoid having updateCart()
in two different places:
function addToCart(pizza, size)
{
// find the first item where the condition is true,
// or undefined if there is none
var sameSizeItem = Cart.find(function (item) {
return pizzaAndSizeAreTheSame(item, pizza, size);
});
if (sameSizeItem) {
sameSizeItem.quantity++;
} else {
Cart.push({
pizza: pizza,
size: size,
quantity: 1
});
}
updateCart();
}
If the environment(s) you're targeting do not all support Array#find
, you can get a polyfill from MDN.
function addToCart(pizza, size) {
var res = Cart.some(function(cartItem)) {
if(pizzaAndSizeAreTheSame(cartItem, pizza, size)) {
cartItem.quantity++;
updateCart();
//Want go out from addToCart if this return is reached
return true;
}
return false;
});
if(res) {
return;
}
//Don`t want the code run after return;
Cart.push({
pizza: pizza,
size: size,
quantity: 1
});
updateCart();
}
You could improve by making your cart an object that has methods for adding to it and a quantities
property. That property would have as keys the different combinations of pizza and size, and as values the quantities for them. This would replace the array you currently have.
Then you can access these properties directly without having to loop at all, and without the need for the function pizzaAndSizeAreTheSame
.
Here is an example of you could implement that:
function Cart() { // Put all cart functionality in one object/constructor
// Make the list of items in the cart an object instead of an array
this.quantities = {};
}
// Define the methods on the Cart prototype
Cart.prototype = {
update: function() {
// whatever logic you had in updateCart
},
add: function(pizza, size) {
var key = pizza + '|' + size;
this.quantities[key] = (this.quantities[key] || 0) + 1;
this.update();
},
toArray: function() { // In case you need your original format also
return Object.keys(this.quantities).map(function (key) {
return {
quantity: this[key],
pizza: key.split('|')[0],
size: key.split('|')[1]
};
}.bind(this.quantities))
}
};
// Demo: create a cart and add items to it.
cart = new Cart();
cart.add('Four seasons', 'medium');
cart.add('Four seasons', 'medium');
cart.add('Vegetarian', 'large');
console.log(cart.toArray());
.as-console-wrapper { max-height: 100% !important; top: 0; }