【问题标题】:forEach/for...in not returning values? [duplicate]forEach/for...in 不返回值? [复制]
【发布时间】:2017-04-22 15:51:51
【问题描述】:

所以我有点困惑,我正在解决freeCodeCamp 上的一个挑战。

challenge 内容如下

一切都是真实的

检查谓词(第二个参数)在集合的所有元素(第一个参数)上是否为真。

解决了,但我不明白为什么我必须采取额外的步骤。我的代码是这样的:

function truthCheck(collection, pre) {
    collection.forEach(function(element) {
        for (key in element) {
            if (!element.hasOwnProperty(pre)) {
                return false;
            } else if (key === pre) {
                if (!Boolean(element[key])) {
                    return false;
                }
            }
        }
    });
    return true;
}

truthCheck([
    {"user": "Tinky-Winky", "sex": "male"},
    {"user": "Dipsy"},
    {"user": "Laa-Laa", "sex": "female"},
    {"user": "Po", "sex": "female"}
], "sex");

所以在这种情况下它应该会失败,因为collection 中的第二个元素没有sex 属性。如果pre 参数,或者在这种情况下sex 不是一个真实值,您也会收到失败。

当这些被击中时(它们是什么,我可以通过控制台日志来判断)但我认为它会跳出循环并从 truthCheck 函数返回.....但它没有,它最终会返回true。

我可以通过定义一个变量然后将该值设置为 false 然后在最后返回该变量来规避这个问题。有没有更好的办法?似乎这些回报应该突破truthCheck 函数?我错过了什么吗?

【问题讨论】:

  • Foreach 不处理返回值。您可能希望使用常规的 for 循环。
  • 仅供参考:if (Boolean(element[key])) 更容易写成if (element[key])。这将检查某个值是否设置为评估为 true 的值。如果你想知道一个对象是否有某个key(而不是有某个value),使用if (element.hasOwnProperty(key))

标签: javascript


【解决方案1】:

正如其他答案所解释的,这是没有意义的:

collection.forEach(function () {
  // do something
  return false;
});

因为array#forEach 根本不关心其工作函数的返回值。它只是为每个数组元素执行工作函数。

你可以使用worker函数来设置一个外部变量:

function truthCheck(collection, pre) {
  var allAreTruthy = true;
  collection.forEach(function (elem) {
    // if this ever flips allAreTruthy to false, it will stay false
    allAreTruthy = allAreTruthy && elem[pre];
  });
  return allAreTruthy;
}

但有更好的方式来表达这一点。

检查谓词(第二个参数)在集合的所有元素(第一个参数)上是否为真。

可以解释为集合的每个元素在特定键处都具有真实值。”

function truthCheck(collection, pre) {
  return collection.every(function (elem) { return elem[pre]; });
}

可以解释为没有集合中的元素在特定键处具有虚假值(或完全缺少键)。”

或者,由于Array#none 方法实际上并不存在,“集合中没有一些元素在特定键处具有虚假值。”

function truthCheck(collection, pre) {
  return !collection.some(function (elem) { return !elem[pre]; });
}

使用Array#some 的好处是,一旦满足它所寻找的条件,它就会停止迭代数组。如果您的数组有很多元素,这将意味着提高性能。对于短数组,使用Array#everyArray#forEach 没有太大区别。

以上在语义上等价于

function truthCheck(collection, pre) {
  var i;
  for (i = 0; i < collection.length; i++) {
    if (!collection[i][pre]) return false;
  }
  return true;
}

由于 JS 对象在访问尚未设置的键时仅返回 undefined,因此在这里检查 hasOwnProperty 是多余的。

【讨论】:

    【解决方案2】:

    您不能从 ForEach 循环中返回任何内容。默认情况下它将返回undefined

    正如官方文档Array.prototype.forEach() - JavaScript | MDN 所说:

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

    所以你可以使用一个非常简单的for..in循环,例如:

    for(var c in collection){
        // Do whatever you want
    } 
    

    【讨论】:

      【解决方案3】:

      [collection].forEach 的 javascript 不像普通循环那样工作。除非你让它抛出异常,否则没有办法提前结束它。

      您所期望的行为是您对 javascript for 循环所期望的行为,但由于 forEach 对每个循环对象使用回调函数,因此您只退出回调函数而不是 forEach。另外值得注意的是,在您的代码中,您有一个 for 循环,其中有一个 return。此循环中的返回块仅中断此循环,而不是 forEach(我之前提到过,除非另有说明,否则不能提前终止)

      如您所见,forEach 主要用于迭代所有元素,而不是对每个迭代元素进行条件检查。

      【讨论】:

        【解决方案4】:
        function truthCheck(collection, pre) {
          return collection.every(function (person) { return !!person[pre]; });
        }
        

        【讨论】:

        • return person[pre]; 足以进行真实性检查。
        • Tomalak 你是对的,我只是转换为布尔值以保持类型一致性。
        • every 而言,没有任何区别。 :)
        【解决方案5】:

        您对集合的每个元素执行一个函数。这个函数检查那个元素返回了一些东西。但是该返回值不会影响外部函数的结果。由于外部函数不依赖于内部函数,因此您的结果总是正确的。

        如果您定义一个变量,请将其设置为 false 并在最后返回该变量会起作用,但效率会很低。让我们考虑以下场景。您找到了一个没有目标键的元素。所以现在你应该回​​来,但你不能。您必须自己完成整个系列。 forEach 循环不会让您在没有mess 的情况下退出。因此,一个更好的主意是 for 循环。如果找到您要查找的内容,您可以退出退出 for 循环

        稍微简单一点的方法是:

        function truthCheck(collection, pre) {
            //iterate thrugh your collection
            for (var c in collection){
                //get keys of element as an array and check if pre is in that array
                if( Object.keys(collection[c]).indexOf(pre) == -1){
                    // pre was not found
                    return false;
                }
            }
            return true;
        }
        

        【讨论】:

          猜你喜欢
          • 2016-11-09
          • 2023-03-29
          • 1970-01-01
          • 2018-11-14
          • 1970-01-01
          • 2021-07-08
          • 1970-01-01
          • 2017-11-06
          • 1970-01-01
          相关资源
          最近更新 更多