Javascript 如何使用0.reduce(和0.each)从underline.js重新写入0.every/0.all
我正在为许多标准的underline.js函数重新编写底层代码,以提高我的JavaScript技能,我有点被Javascript 如何使用0.reduce(和0.each)从underline.js重新写入0.every/0.all,javascript,underscore.js,Javascript,Underscore.js,我正在为许多标准的underline.js函数重新编写底层代码,以提高我的JavaScript技能,我有点被.
.
/.\uAll
卡住了。似乎在库本身中,.each
/.all
函数只使用现有的.each
函数编写,但我被鼓励使用我的.reduce
版本编写一个版本(它已经包含了我的.each
)。我已经为下面两个函数提供了代码
第一个测试my。每个
函数(也请参见下文)都失败,其中所有的假值都是使用\.identity
函数(仅返回作为参数输入的值)作为迭代器传入的:
测试:
我有几个问题想知道为什么我的\。每个函数都没有通过上面显示的测试,以及其他多项测试(例如:真/假混合值、未定义值等):
-调用迭代器函数时,是否需要使用iterator.call
或iterator.apply
?如果是的话,我应该使用哪种参数,如何指定参数
-在这里使用.reduce
比只使用.each
有什么好处,特别是当underline.js库不使用.reduce
时
-为什么需要调用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);
}
}
};
\每个=函数(集合、迭代器){
//定义阵列的规范
if(数组.isArray(集合)){
对于(变量i=0;i
_.减少:
_.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;
};
\uu0.reduce=函数(集合、迭代器、累加器){
//如果未给出明确的起始值,则添加设置累加器的条件。
如果(参数长度<3){
累加器=集合[0];
}
_.每个(集合、函数(值){
累加器=迭代器(累加器,值);
});
回流蓄能器;
};
您的测试没有通过,因为它没有按预期返回false
(尽管它返回了一个false值)
返回iterator(item)&&allFound
时,如果iterator(item)
为false(但不是false
),则不会返回false
,而是返回iterator(item)
的值。要亲自验证这一点,请打开一个REPL,然后键入undefined&&true
;结果将是未定义
,而不是错误
因此,如果希望它显式返回false
,而不仅仅是一个false值,那么必须将其强制为布尔值。您可以执行布尔(truthy\u或\u false\u值)
或!!真实值或虚假值
。我通常更喜欢后者,因此请更改您的实现:
_.every = function(collection, iterator) {
return _.reduce(collection, function(allFound, item) {
return !!iterator(item) && allFound;
}, true);
};
你的其他问题:
调用迭代器函数时,是否需要使用iterator.call或
迭代器.apply?如果是的话,我应该使用哪种参数,如何指定参数
这取决于你的目标是什么call
和apply
主要用于控制函数体中this
关键字的值。JavaScript的一些内置数组方法(如array.prototype.map
和array.prototype.filter
)采用thisArg
,这就是提供的使用调用或应用进行回调的方法。至于call
和apply
之间的区别,那只是参数的处理方式。有关更多详细信息,请参阅
在这里使用reduce
而不仅仅是每个有什么好处,
尤其是当underline.js库不使用reduce
可能没有,或者很少。可能存在性能差异,但最好的方法是分析这两种方法
为什么需要调用return两次,调用
_.reduce函数,并且一旦在u.reduce中定义的匿名函数中
如果您想要一个函数——任何函数——返回一个值,那么必须从该函数中调用return。您不能期望从内部函数调用return
,而期望封闭函数神奇地理解它应该反过来返回被调用函数的值。如果未显式调用return
,则某些语言默认返回函数中最后一个表达式的值,这可能是方便的,也可能是混乱的,具体取决于您的角度。如果您有使用这种语言的经验(例如Ruby),那么所有的return
语句对您来说可能有点过分
作为编辑说明,我觉得对于测试函数来说,iterator
是一个糟糕的命名选择。它实际上并不是迭代任何东西(作为参数的函数正在进行任何迭代)。更好的名称可能是非常通用的回调
或cb
。该术语表示将值映射到true
或false
的函数,这是我首选的术语。另一个常见的选择是简单的test
,因为它毕竟只是一个对其参数执行二进制筛选的函数
_.every = function(collection, iterator) {
return _.reduce(collection, function(allFound, item) {
return iterator(item) && allFound;
}, true);
};
_.every = function(collection, iterator) {
return _.reduce(collection, function(allFound, item) {
return !!iterator(item) && allFound;
}, true);
};