gpt4 book ai didi

javascript - 如何使用 _.reduce(和 _.each)从 Underscore.js 重写 _.every/_.all

转载 作者:搜寻专家 更新时间:2023-11-01 04:16:52 30 4
gpt4 key购买 nike

我正在为许多标准的 Underscore.js 函数重写底层代码,以提高我的 JavaScript 技能,但我有点受困于 _.every/ _.全部。似乎在库本身中,_.every/_.all 函数仅使用现有的 _.each 函数编写,但是我被鼓励使用我的 _.reduce 版本编写一个版本(它已经合并了我的 _.each 版本)。我在下面提供了这两个函数的代码。

第一个测试我的 _.every 函数(也见下文)失败是一个使用 _.identity 函数传递所有错误值的测试(只需返回作为参数输入的值)作为迭代器:

测试:

  it('fails for a collection of all-falsy results', function() {
expect(_.every([null, 0, undefined], _.identity)).to.equal(false);
});

关于为什么我的 _.every 函数没有通过上面显示的测试以及其他多项测试(例如,混合真/假值、未定义值等),我有几个问题:

-调用iterator函数时,需要使用iterator.call还是iterator.apply?如果是这样,我应该使用哪个以及如何指定参数?

-在这里使用 _.reduce 而不是 _.each 有什么好处,特别是当 Underscore.js 库不使用 _ 时。减少?

-为什么return需要调用两次,一次是在调用_.reduce函数时,一次是在_.reduce中定义的匿名函数中(我'在构建使用 _.map 函数的函数时,您是否也想知道这一点)?对我来说,我似乎正在返回 _.reduce 函数的结果,它已经返回了一些东西。

_.每:

  _.every = function(collection, iterator) {
// TIP: Try re-using reduce() here.
return _.reduce(collection, function(allFound, item) {
return iterator(item) && allFound;
}, true);
};

_.每个:

_.each = function(collection, iterator) {
// define spec for arrays
if (Array.isArray(collection)) {
for(var i = 0; i < collection.length; i++) {
iterator(collection[i], i, collection);
}
}

// define spec for objects
else {
for(var key in collection) {
iterator(collection[key], key, collection);
}
}
};

_.减少:

  _.reduce = function(collection, iterator, accumulator) {

// add condition to set accumulator if no explicit starting value is given.
if (arguments.length < 3) {
accumulator = collection[0];
}

_.each(collection, function(value) {
accumulator = iterator(accumulator, value);
});

return accumulator;
};

最佳答案

您的测试未通过,因为它没有按预期返回 false(尽管它返回的是错误值)。

_.every = function(collection, iterator) {
return _.reduce(collection, function(allFound, item) {
return iterator(item) && allFound;
}, true);
};

当您返回 iterator(item) && allFound 时发生的事情是,如果 iterator(item) 是假的(但不是 false),它不会返回false,而是返回iterator(item)的值。要自己验证这一点,请打开一个 REPL,然后键入 undefined && true;结果将是 undefined,而不是 false

因此,如果您希望它显式返回 false,而不仅仅是一个假值,您必须将其强制转换为 bool 值。您可以执行 Boolean(truthy_or_falsey_value)!!truthy_or_falsey_value。我通常更喜欢后者,因此请更改您的实现:

_.every = function(collection, iterator) {
return _.reduce(collection, function(allFound, item) {
return !!iterator(item) && allFound;
}, true);
};

您的其他问题:

When calling the iterator function, do I need to use iterator.call or iterator.apply? If so, which do I use and how do I specify arguments?

这取决于你的目标是什么。 callapply 主要用于控制函数体中 this 关键字的值。一些 JavaScript 的内置数组方法(如 Array.prototype.mapArray.prototype.filter)接受一个 thisArg,这就是提供使用 callapply 执行回调。至于 callapply 之间的区别,只是参数的处理方式不同。参见 this answer了解更多详情。

What benefit is there to using reduce here rather than just each, especially when the Underscore.js library does not use reduce?

可能没有,或者很少。可能存在性能差异,但最好的找出方法是分析这两种方法。

Why does return need to be called twice, once when calling the _.reduce function, and once within the anonymous function defined within _.reduce

如果您想要一个函数——任何函数——返回一个值,您必须从该函数内部调用 return。您不能期望从内部函数调用 return,并期望封闭函数神奇地理解它应该反过来返回被调用函数的值。如果未显式调用 return,某些语言默认返回函数中最后一个表达式的值,这要么方便,要么令人困惑,具体取决于您的观点。如果您有使用过这种语言(例如 Ruby)的经验,那么所有的 return 语句对您来说可能有点过分。

作为编者注,我觉得 iterator 是测试函数的一个糟糕的命名选择。它实际上并没有迭代任何东西(它作为参数的函数正在做任何迭代)。更好的名称可能是非常通用的 callbackcb。术语"predicate"表示将值映射到 truefalse 的函数,这是我的首选术语。另一个常见的选择是简单地 test,因为毕竟它只是一个对其参数执行二元过滤的函数。

关于javascript - 如何使用 _.reduce(和 _.each)从 Underscore.js 重写 _.every/_.all,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24298493/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com