返回值时,`each` 与 `for-loop` 有何不同?

How is `each` different from `for-loop` when returning a value?

我创建了我的 each 函数来模拟 Underscore.js 的 _each() 用于我的 Javascript 学习。

var each = function(list, iteratee) {
    if (Array.isArray(list)) { // list is array
        for (var i = 0; i < list.length; i++) {
            iteratee(list[i], i, list);
        }
    } else if (list.constructor === Object) { // list is object
        for (var key in list) {
            iteratee(list[key], key, list);
        }
    }
};

然后我想创建一个函数 find,它也可以从 Underscore.js 获得。此函数查看 list、return 中第一个通过真值测试 (predicate) 的每个值,或 undefined 如果没有值通过测试。函数 returns 一旦找到可接受的元素并且不会遍历整个列表。

这是我想出的 find 版本。

var find = function(list, predicate) {
    each(list, function(elem){
        if (predicate(elem)) {
            return elem;
        }
    });
};

我认为它会在找到通过外部谓词函数测试的元素的真值后立即 return 一个值。但相反,它给了我一个 undefined.

下面的代码如我所料。但为什么他们会提供不同的输出?

var find = function(list, predicate) {
    if (Array.isArray(list)) { // list is array
        for (var i = 0; i < list.length; i++) {
            if (predicate(list[i])) {
                return list[i];
            }
        }
    } else if (list.constructor === Object) { // list is object
        for (var key in list) {
            if (predicate(list[key])) {
                return list[key];
            }
        }
    }
};

我不明白的是,当我将 each 包含在我的 find 函数中时,为什么它没有像我预期的那样工作。他们不会只是表达方式不同吗?也就是说,一个是函数式风格,一个不是?

这是由于缺少return声明造成的。 每个函数迭代查找但不 return 任何东西。 return 谓词中的语句 returns 输出到每个函数的不期望的地方

工作函数示例:

var find = function(list, predicate) {
     var res = undefined/null/whatever;
     each(list, function(elem) {
         if (predicate(elem)) {
             res = elem;
         }
     });
     return res;
};

但是这个函数效率不高,因为它不会在找到结果时停止

这与 return 的工作原理有关。让我们看看您的代码:

var find = function(list, predicate) {
    // you pass list and an anonymous callback to `each`
    each(list, function (elem) {
        // if this condition is true
        if (predicate(elem)) {
            // return elem
            return elem;
        }
    });
}

问题是 return elem 适用于匿名回调,而不是 find 函数。

如果您希望能够 "break" each 循环,您可以检查 each.[=21= 中 for 循环每次迭代的当前状态]

// only going to write for arrays
var each = function (list, iteratee) {
    for (var i = 0; i < list.length; i++) {
        if (iteratee(list[i], i, list)) continue;
        else break;
    }
});
// then in find:
var find = function (list, predicate) {
    var ret = null
    each(list, function(elem) {
        if (predicate(elem)) {
            ret = elem;
            return false;    // return false, since we no longer wish to continue
        }
    });
    return ret;
};

第二种解决方案是在 each 循环中 return:

var each = function (list, iteratee) {
    for (var i = 0; i < list.length; i++) {
        if (iteratee(list[i], i, list)) {
            continue;
        } else {
            return list[i];
        }
    }
    // didn't find anything, so `return null`
    return null;
});
var find = function (list, predicate) {
    return each(list, function(elem) {
        // if `predicate`, return false, so the loop breaks
        return !predicate(elem);
    });
};

我对这个解决方案的唯一问题是它扭曲了 each 的含义。 each 直觉上意味着 "go through everything," 而第二个解决方案不一定如此。