検索アルゴリズムに関する限り、あなたが持っている解決策はおそらく「最良」であり、必ずしもそれを変更することを提案するわけではありません(または、アルゴリズムの代わりにマップを使用するように変更します)が、質問は特に興味深いものですJavaScript 言語の機能特性に関連して、いくつかの考えを提供したいと思います。
方法 1
以下は、代わりに関数の引数として使用されますが、関数内で変数を明示的に宣言しなくても機能するはずです。また、少し簡潔ではありますが、非常に簡潔です。
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
( 経由で) を使用します。(おそらく、これらの再帰呼び出しの 1 つが答えを返します。答えにならないものは を返します。)Array.prototype.map
this
find
undefined
- 「見つかった項目」配列をフィルタリングして
undefined
、配列内の結果が削除されるようにします。
- 配列の最初の項目を返し、それを終了します。
- 配列に最初の項目がない場合は、
undefined
が返されます。
方法 2
この問題を解決するための別の試みは、次のようになります。
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
と のすべての子を含む単一の大きな 1 次元配列を作成しobj
ます。
- 次に、配列内のオブジェクトにof が
filter
必要であるという基準に基づいています。id
match_id
- 最初の試合を返します。
方法 1と方法 2はどちらも興味深いものですが、一致する ID が見つかった後も検索を続けるというパフォーマンス上の欠点があります。彼らは検索が終わるまで自分が必要なものを持っていることに気付きません。これはあまり効率的ではありません。
方法 3
確かに効率化は可能ですし、これであなたが興味を持っていたものにかなり近づいたと思います。
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
それでも、これらは非常に小さなパフォーマンスの損失です。
方法 4
最後に、このメソッドはリクエストの範囲に適合しませんが、アプリケーションで可能であればはるかに優れたパフォーマンスであり、考慮すべき点です。オブジェクトにマップする 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];
これは、メモリリークを防ぐために必要です。