2012-08-24 69 views
7

假設我想在window的所有聲明變量中搜索一個值,例如'StackOverflow'。 我可以用這個代碼做到這一點:遞歸搜索全局變量及其屬性中的值

function globalSearch(obj, value) { 
    for(var p in obj) 
     if(obj[p] == value) 
      return(p); 
} 
globalSearch(window, 'StackOverflow'); 

此代碼將返回具有此值的變量的名稱(或沒有返回值)。 因此,如果我已經聲明一個值爲'StackOverflow'的變量,它將成功找到它。

我的問題是,我想更深入和搜索直通window的對象(和它自己的嵌套對象)也實現這樣的結果:

var x = 'StackOverflow'      // returns 'x' 
var y = { a : 'StackOverflow' }    // returns 'y.a' 
var z = { a : { b: 'StackOverflow' } }  // returns 'z.a.b' 

我在與歷史遺留問題對象的方法。有沒有辦法做到這一點?

+0

你是什麼意思的問題與繼承方法? –

回答

11

深度搜索,但沒有遞歸函數調用

功能遞歸有內部堆棧限制和浪費內存。

附加功能添加

在檢索陣列的形式

遞歸對象保護;它不會佔用太多的內存,因爲對象只能作爲引用存儲。

如果對象本身與該值匹配,則返回true。否則它會返回'',這將匹配爲false。

數組使用尖括號表示法。

代碼

function globalSearch(startObject, value) { 
    var stack = [[startObject,'']]; 
    var searched = []; 
    var found = false; 

    var isArray = function(test) { 
     return Object.prototype.toString.call(test) === '[object Array]'; 
    } 

    while(stack.length) { 
     var fromStack = stack.pop(); 
     var obj = fromStack[0]; 
     var address = fromStack[1]; 

     if(typeof obj == typeof value && obj == value) { 
      var found = address; 
      break; 
     }else if(typeof obj == "object" && searched.indexOf(obj) == -1){ 
      if (isArray(obj)) { 
       var prefix = '['; 
       var postfix = ']'; 
      }else { 
       var prefix = '.'; 
       var postfix = ''; 
      } 
      for(i in obj) { 
       stack.push([ obj[i], address + prefix + i + postfix ]); 
      } 
      searched.push(obj); 
     } 
    } 
    return found == '' ? true : found; 
} 

問題

,而沒有經過INTIAL變量名到函數,我們不能從一開始就返回完全合格的變量名。我想不出一個解決方案,如果有解決方案,我會感到驚訝。

帶空格的變量名作爲對象的關鍵字是有效的,與其他無效變量名一樣,它只是表示必須使用尖括號來處理該值。我可以想到幾個解決方案。正則表達式檢查每個變量名稱以確保它是有效的,如果不是,則使用尖括號表示法。最重要的問題是,reg-ex只是一個頁面。或者,我們只能使用尖括號,但這對OP的原始問題並不真實。

數組'搜索'上的indexOf調用可能在非常大的對象上有點沉重,但我還沒有想到替代方案。

改進

除了清理代碼一點,它也將是很好,如果函數返回匹配的數組。這也引發了另一個問題,即返回的數組不包含對遞歸對象的引用。也許該函數可以接受結果格式配置參數。

+0

幾乎在螢火蟲控制檯的任何頁面上運行這個,我得到「操作是不安全的。」我正在搞一些錯誤捕捉的方案,但我不確定我會找到足夠好的東西來添加。也許別人可以做出改進來解決這個問題? – eternalnewb

4

這應該工作。它使用遞歸來實現結果。

function globalSearch(obj, value) { 
    for(var p in obj) 
     if(obj[p] == value){ 
      return(p); 
     }else if(typeof obj[p] == "object" && obj[p] != obj){ 
      var te = globalSearch(obj[p], value); 
      if(te!=false){ return p + "." + te } 
     } 
    return false; 
} 
0

使您的解決方案遞歸。如果你有一個對象,再次調用你的函數。

function globalSearch(obj, value) { 
    for(var p in obj) { 
     if (obj[p] == value) { 
      return(p); 
     } else if (typeof obj[p] === "object") { 
      var recursiveCheck= globalSearch(obj[p], value); 
      if (recursiveCheck) { 
       return p + "." + recursiveCheck; 
      } 
     } 
    } 
} 
globalSearch(window, 'StackOverflow'); 

我敢打賭,大多數瀏覽器會針對太多循環發出警告。

+2

請注意,你的函數被''window'作爲'obj'卡住了。 – Ravan

+0

@Ravan:查看我的答案,解釋了這一點。 – JCOC611