尽管就搜索算法而言,您拥有的解决方案可能是“最好的”,而且我不一定建议更改它(或者我会更改它以使用地图而不是算法),但这个问题对我来说很有趣,尤其是关于 JavaScript 语言的功能属性,我想提供一些想法。
方法一
以下应该可以工作,而不必在函数中显式声明变量,尽管它们被用作函数参数。它也很简洁,虽然有点简洁。
var map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return this.id == match_id ? this : map(this, function(u) {
return find.call(u, match_id);
}).filter(function(u) { return u; })[0];
};
这个怎么运作:
- 我们测试看看是否
this.id == match_id
,如果是,返回this
。
- 我们使用
map
(via Array.prototype.map
) 转换this
为“找到的项目”数组,这些“找到的项目”是使用对该find
方法的递归调用找到的。(假设,这些递归调用之一将返回我们的答案。没有得到答案的将返回undefined
。)
- 我们过滤“找到的项目”数组,以便
undefined
删除数组中的任何结果。
- 我们返回数组中的第一项,并将其称为退出。
方法二
解决此问题的另一种尝试可能如下所示:
var concat = Function.prototype.call.bind(Array.prototype.concat),
map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return (function buildObjArray(o) {
return concat([ o ], map(o, buildObjArray));
})(this).filter(function(u) { return u.id == match_id })[0];
};
这个怎么运作:
buildObjArray
构建一个单一的、大的、一维数组,包含obj
和所有obj
的孩子。
- 然后我们
filter
基于数组中的对象必须具有id
of 的条件match_id
。
- 我们返回第一场比赛。
Method 1和Method 2虽然很有趣,但它们的性能缺点是即使在找到匹配的 id 后它们仍会继续搜索。他们直到搜索结束才意识到他们拥有所需的东西,这不是很有效。
方法三
提高效率当然是可以的,现在我觉得这个真的很接近你感兴趣的东西了。
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
obj.find = function(match_id) {
try {
(function find(obj) {
if(obj.id == match_id) throw this;
forEach(obj, find);
})(obj);
} catch(found) {
return found;
}
};
这个怎么运作:
- 我们将整个
find
函数包装在一个try
/catch
块中,这样一旦找到一个项目,我们就可以throw
停止执行。
- 我们在其中创建了一个内部
find
函数 (IIFE) try
,我们引用它来进行递归调用。
- 如果
this.id == match_id
, 我们throw this
, 停止我们的搜索算法。
- 如果不匹配,我们递归调用
find
每个孩子。
- 如果匹配,
throw
则被我们的catch
块捕获,并found
返回对象。
由于该算法能够在找到对象后停止执行,因此它的性能将接近您的,尽管它仍然具有try
/catch
块的开销(在旧浏览器上可能很昂贵)并且forEach
比典型的for
循环慢。这些仍然是非常小的性能损失。
方法四
最后,虽然这种方法不符合您的要求,但如果可能的话,它在您的应用程序中的性能要好得多,值得考虑。我们依赖于映射到对象的 id 映射。它看起来像这样:
// Declare a map object.
var map = { };
// ...
// Whenever you add a child to an object...
obj[0] = new MyObject();
// .. also store it in the map.
map[obj[0].id] = obj[0];
// ...
// Whenever you want to find the object with a specific id, refer to the map:
console.log(map[match_id]); // <- This is the "found" object.
这样,根本不需要任何find
方法!
通过使用这种方法,您的应用程序的性能提升将是巨大的。如果可能的话,请认真考虑。
但是,当您不再引用该对象时,请小心从地图中删除该对象。
delete map[obj.id];
这是防止内存泄漏所必需的。