2012-04-27 28 views
3

私は最近、OPがオブジェクトのプロパティへのパスを探したかったので、this questionが尋ねられたので、私はpsuedocodeで答えました。実際には解決策を書く。しかし、問題は私にとっては面白かったので、とにかく解決策を書こうとした。ここで私は、これまでに作ってみたものです:オブジェクトを検索しようとすると無限ループが発生する

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

アイデアは、私は、オブジェクトのプロパティのそれぞれを表すNodeオブジェクトにthis.searchNode()を呼ぶだろうということです。 searchNode()は、現在のオブジェクトを子ノードのそれぞれにparentとして渡して、結果のプロパティノードのそれぞれでそれ自身を呼び出します。検索する関数が見つかった場合は、reconstructPathRecursive()と呼びます(各ノードの親プロパティを使用しています)。

しかし、「最大コールスタックサイズを超えました」というメッセージが表示されます。これを実行するとエラーが発生しますlive test私はそれが何とか無意味なループを間違って書いたことを意味します。私のロジックの欠陥はどこにありますか?その無限ループはどこに潜んでいましたか? console.logは、searchNodeが何度も繰り返し呼び出されていることを示していますが、オブジェクトが空でない場合にのみ呼び出しています。オブジェクトをどこにでも参照することはできません(私は考えません...) 、私は本当にここでうんざりしています。

編集:私はsearchNode()機能でthis.objにそれを呼び出すことができるように、グローバル関数へのノードの機能からisEmptyを変更するには、多少のコード​​を更新しました。これまでは、Nodes(これは常に少なくとも2つのプロパティを持つため、無限ループになります)で呼び出され、参照されるオブジェクトでは呼び出されませんでした。これは修正されましたが、エラーは解決されません。

別の編集:見つけて別のエラーを修正しました(Satyajitの答えを参照)。しかし、無限ループをやっている。

答えて

1

それは子としての地位が含まれているので、これは

var arr = []; 
arr[0] = arr; 

に失敗します。 Node関数は、親が子と同じノードの無制限のリストを作成します。

循環オブジェクトグラフを処理するには、既に訪問したものを追跡し、再訪しないようにする必要があります。これは、オブジェクトセットを持たないためJavaScriptでは難しいです。

あなたが訪問したオブジェクトのリストを維持し、objが出、またはあなたがオブジェクトを訪問したかどうかを伝えるために、特殊なオブジェクトプロパティ(ブレッドクラム)を使用しようとすることができるかどうかを確認することができます。適切にクリーンアップしないか、他の誰かがそのプロパティを使用するか、他のコードがEcmaScript 5をフリーズすると、ブレッドクラムが失敗します。


EDIT:

あなたが実際に子供にパスを見つけるときにも、子ループから抜け出す必要があります。

path = children[i].searchNode(); 

path = children[i].searchNode(); 
if (path) { return path; } 

EDITにすべきである:

サタジットが指摘するように、"gotcha"がプロパティ値です。

"gotcha"[0] === "g""g"[0] === "g"以降、サイクルになるまでに時間がかかりません。

私は最近Chromeで

alert("gotcha".hasOwnProperty(0)); 
for (var k in "gotcha") { alert(k); } 

を行うと、私は "真" のアラートを取得し、 "0"、 "1"、...、 "5"。

Stringオブジェクトは、他のネイティブのECMAScriptオブジェクト(8.12.1)に使用される[[GetOwnProperty]]内部メソッドのバリエーションを使用:

これはセクション15.5.5.2に概説されるように最新のブラウザ上の標準的な動作です。この特殊な内部メソッドは、Stringオブジェクトの個々の文字に対応する名前付きプロパティへのアクセスを追加するために使用されます。

これらのプロパティは、そのセクションの箇条書き9のために列挙できます。

+0

私はどこでそれをやっているのか詳しく説明できますか?私はどこにも見ません。すでに私が訪れたことをどのように追跡するかを実装する方法を見ていきます。助けてくれてありがとう! –

+0

@ElliotBonneville、問題は、 'myObj'が周期的であることです。あなたは 'myObj'がどのように派生しているかを示していないので、コードであなたを指摘できません。 –

+0

私が提供したjsFiddleを訪問しましたか?今すぐリンクを更新してください。また、myObjは単なる別のオブジェクトです。あなたはそれがどのように得られたかを見ます。それは単なるテストオブジェクトなので、私はその上で自分の関数をテストすることができます。 –

2

プロパティnullRootは文字列であり、javascriptオブジェクトではありません。 isEmpty関数を実行するとfalseを返すことはなく、無限ループに投げ込まれます。それはあなたが値段として "つかみ"を置くことはほとんど預言的です。

+0

私は実際にちょっと前にそれを捕まえました。私の答えを更新するのを忘れました(いいえ、それは私の問題を解決しませんでした)。そして、はい、私はそれがおそらく私がラインのどこかに私を得るだろうと知っているので、 "つかみ"を入れました... :) –

+0

ニースキャッチ。あなたが 'isEmpty'の振る舞いを指摘するまで、' 'g" [0] === "g" 'から空でない文字列が循環オブジェクトであることは私には起こりませんでした。 –

関連する問題