【问题标题】:Return from a method in which forEach() array method was called. JavaScript从调用 forEach() 数组方法的方法返回。 JavaScript
【发布时间】:2017-08-14 01:48:09
【问题描述】:

我正在使用从 JavaScript 中的数组调用的 forEach() 方法。当我在为数组中的每个元素调用的方法内部某处写return; 时,我从为特定元素调用的方法中返回,仅此而已。但我真正想要的是从数组调用 forEach() 的方法中返回。代码如下:

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

这是我到目前为止提出的解决方案:

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

我想知道有没有更好的解决方案。

与那个问题相比:How to short circuit Array.forEach like calling break? 我对了解 forEach() 循环中的新方法不感兴趣,我想打破的不是 forEach(),而是包含 forEach() 调用方方法。

【问题讨论】:

  • pizzaAndSizeAreTheSame 是否在比较以检查是否找到了什么?如果是这样,请使用find 或some!
  • 从语句返回的唯一方法是抛出/捕获:stackoverflow.com/questions/2641347/…
  • 对,.some() 就是您要找的。如果回调返回true,则迭代停止,.some() 也返回true。
  • 我的首选方式是使用 lodash... _.forEach 可以处理 return false;打破循环,任何变量设置为 true 表示退出函数。

标签: javascript arrays foreach ecmascript-5


【解决方案1】:
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();
}

【讨论】:

  • 它是否从 addToCart() 中返回?
  • 是的,它首先从some返回,然后使用if (res)从addToCart返回。 +1
  • @trincot,这与我的解决方案没有什么不同。
  • 不一样。只需比较循环中的迭代次数...
【解决方案2】:

引用Mozilla Developer Network:

除了抛出异常之外,没有其他方法可以停止或中断 forEach() 循环。如果您需要这种行为,则 forEach() 方法是错误的工具,请改用普通循环。如果您正在测试谓词的数组元素并且需要布尔返回值,则可以使用 every() 或 some() 代替。如果可用,新方法 find() 或 findIndex() 也可用于在真谓词上提前终止。

话虽如此,我相信您设置标志以返回函数的解决方案是最合适和最简单的。

【讨论】:

    【解决方案3】:

    您可以使用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();
    }
    

    稍加调整,您就可以避免在两个不同的地方出现updateCart():

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

    如果您的目标环境并非全部支持Array#find,您可以获取polyfill from MDN。

    【讨论】:

      【解决方案4】:

      您可以通过使您的购物车成为具有添加方法和quantities 属性的对象来改进。该属性将以披萨和大小的不同组合作为键,并将它们的数量作为值。这将替换您当前拥有的数组。

      然后你就可以直接访问这些属性,根本不需要循环,也不需要函数pizzaAndSizeAreTheSame。

      这是一个你可以实现的例子:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多