我不喜欢循环,然而这似乎很容易用循环解决,很难用函数式编程。下面是循环版本:
for(var i = 0; i < collection.length; i++) {
var result = collection[i].findById(id);
if (result) {
return result;
}
}
因为这是一个常见的模式,所以我希望在lodash中找到一个功能性的替代方案。然而,我能想到的最好的是:
return _.first(_.compact(_.map(collection, e => e.findById(id)));
这不仅很难看,而且当第一个元素返回真值后,它将对集合中的每个元素调用findById。
你如何实现这个?
如果你有这两个函数
let uncurry = f => (x,y) => f(x)(y);
let reduce = f => i => xs => xs.reduce(uncurry(f), i);
你可以写一个简单的findById
let findById = id => reduce(y => x => y || x.findById(id))(null);
像这样使用
findById(15)(collection); // => result | null
它仍然会遍历集合中的每个项目,但它是短路求值的,并且只会调用findById
,直到找到结果。
这是ES5
var uncurry = function uncurry(f) {
return function (x, y) {
return f(x)(y);
};
};
var reduce = function reduce(f) {
return function (i) {
return function (xs) {
return xs.reduce(uncurry(f), i);
};
};
};
var findById = function findById(id) {
return reduce(function (y) {
return function (x) {
return y || x.findById(id);
};
})(null);
};
如果你想继续使用下划线/lodash,你可以使用这个
let findById = id => xs =>
_.reduce(xs, (result, x) => result || x.findById(id), null);
嗯,它不是更好,但我想你可以使用some
来实现短路。有点忽略了用函数结构使东西更可读的要点,但它应该工作…
var result;
collection.some(function(datum){
return (result = datum.findById(id)) || return result == true;
});
在ES7规范中也有find
。当你有可用的,你可以做以下事情:
collection.find(function(datum){
return datum.findById(id) !== null;
});
如何:
_.find(collection, function(c) {
return c.findById(id) === true;
});
如果你想使用纯javascript:
function findFirstById(collection, id, pos) {
pos = (typeof pos === 'undefined') ? 0 : pos;
if (pos >= collection.length)
return false;
var result = collection[pos].findById(id);
if (result)
return result;
else
return findFirstById(collection, id, pos + 1);
}
这对你有帮助吗?