在javascript中实现函数递归findById有比这更好的方法吗?



我不喜欢循环,然而这似乎很容易用循环解决,很难用函数式编程。下面是循环版本:

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);
}

这对你有帮助吗?

最新更新