Return from a method in which forEach() array meth

2020-05-06 06:44发布

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 out from the method which was called for a specific element and that is all. But what I actually want is to return out from the method in which array called forEach(). Here is the code:

    function addToCart(pizza, size)
    {
        Cart.forEach(function(cartItem)
        {
            if(pizzaAndSizeAreTheSame(cartItem, pizza, size))
            {
                cartItem.quantity++;
                updateCart();
                //Want go out from addToCart if this return is reached
                return;
            }
        });

        //Don`t want the code run after return;
        Cart.push
        ({
            pizza: pizza,
            size: size,
            quantity: 1
        });
        updateCart();
    }

Here is solution with which I came up so far :

    function addToCart(pizza, size)
{
    var leaveTheMethod = false;
    Cart.forEach(function(cartItem)
    {
        if(pizzaAndSizeAreTheSame(cartItem, pizza, size))
        {
            cartItem.quantity++;
            updateCart();
            leveTheMethod = true;
        }
    });
    if(leaveTheMethod)
        {return;}

    //Don`t want the code run after return;
    Cart.push
    ({
        pizza: pizza,
        size: size,
        quantity: 1
    });
    updateCart();
}

I would like to know are there any better solutions to the problem.

Compared to that question: How to short circuit Array.forEach like calling break? I am not interested in knowing the new method in forEach() loop and I want to break not from forEach() but from encompassing the forEach() caller method.

4条回答
看我几分像从前
2楼-- · 2020-05-06 06:51

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.

查看更多
Evening l夕情丶
3楼-- · 2020-05-06 07:04
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();
}
查看更多
霸刀☆藐视天下
4楼-- · 2020-05-06 07:08

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.

查看更多
Juvenile、少年°
5楼-- · 2020-05-06 07:12

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; }

查看更多
登录 后发表回答