私は最近、OPがオブジェクトのプロパティへのパスを見つけたいというこの質問が出されているのを見たので、実際に解決策を書くのに十分な時間がないと述べて、疑似コードで答えました。しかし、その質問は私にとって非常に興味深いものだったので、とにかく解決策を書こうとしました。これが私がこれまでに思いついたものです:
function isEmpty(obj) {
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
return false;
}
}
return true;
}
function Node(obj, parent, searchTarget) {
this.parent = parent;
this.obj = obj;
this.searchTarget = searchTarget;
this.searchNode = function() {
if(this.obj == this.searchTarget) {
//return this.reconstructPathRecursive();
}
if (!isEmpty(this.obj)) {
var children = [];
for (prop in this.obj) {
if (this.obj.hasOwnProperty(prop)) {
children.push(new Node(this.obj[prop], this, searchTarget));
}
}
var path;
for(var i = 0, len = children.length; i < len; i++) {
path = children[i].searchNode();
if(path) return path;
}
}
}
this.reconstructPathRecursive = function() {
var path = [this], curObj = this.parent;
while (curObj != undefined) {
path.push(curObj);
curObj = curObj.parent;
if(curObj == undefined) break;
}
return path;
}
this.findPath = function() {
return this.searchNode();
}
}
var myObj = {
nullRoot: "gotcha!",
path1: {
myFunc: function() {
alert("Success!");
}
}
}
function findFunctionPath(obj, func) {
return new Node(obj, undefined, func).findPath();
}
var thisFunc = myObj.path1.myFunc;
console.log("--");
console.log(findFunctionPath(myObj, thisFunc));
アイデアはthis.searchNode()
、オブジェクトの各プロパティを表す Node オブジェクトを呼び出すというものです。searchNode()
結果の各プロパティ ノードで自身を呼び出し、現在のオブジェクトを各子ノードの として渡しますparent
。検索する関数が見つかったら、 を呼び出しますreconstructPathRecursive()
。これは、各ノードの親プロパティを使用して、ほとんどそれを行います。
ただし、「最大コール スタック サイズを超えました」というメッセージが表示されます。このライブ テストを実行するとエラーが発生します。どういうわけか誤って無限ループを書いたということだと思います。私の論理のどこに欠陥があり、その無限ループはどこに忍び込んだのでしょうか? console.log
が何度も呼び出されていることを示していsearchNode
ますが、オブジェクトが空でない場合にのみ呼び出しており、オブジェクトにそれ自体への参照をどこにも与えていません (私は考えていません...)。私は本当にここで困惑しています。
編集:isEmpty
Node 関数からグローバル関数に変更するためにコードを多少更新してthis.obj
、searchNode()
関数内で呼び出すことができるようにしました。以前は、参照されるオブジェクトではなく、ノード (常に少なくとも 2 つのプロパティを持つため、無限ループが発生します) でのみ呼び出されていました。それは修正されましたが、エラーは続きます。
別の編集:別のエラーを見つけて修正しました(Satyajitの回答を参照)。ただし、まだ無限ループを取得しています。