2012-08-24 8 views
7

Załóżmy, że chcę wyszukać wartość, taką jak 'StackOverflow', we wszystkich zadeklarowanych zmiennych w window. mogę zrobić z tym kodem:Wyszukiwanie rekursywne wartości zmiennych globalnych i ich właściwości

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

Ten kod zwróci nazwę zmiennej, które mają tę wartość (lub nic nie zwraca). Tak więc, jeśli zadeklarowałem zmienną o wartości 'StackOverflow', zostanie ona pomyślnie znaleziona.

Moim problemem jest to, że chcę iść głębiej i szukać thru obiektów window „S (oraz własnych obiektów zagnieżdżonych) też, aby osiągnąć rezultat takiego:

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

Mam problemy z dziedziczną metody obiektów. Czy jest jakiś sposób na zrobienie tego?

+0

Co rozumiesz przez problemy z dziedzicznymi metodami? –

Odpowiedz

11

Głębokie wyszukiwania, ale bez funkcji rekurencyjnej wzywa

rekurencji funkcjonalna ma swoje granice wewnętrzne i pamięci stosu odpadów.

Dodatkowe funkcje dodane

rekurencyjne ochrony obiektu w postaci szukanego tablicy; Nie zużywa zbyt wiele pamięci, ponieważ obiekty są przechowywane tylko jako odniesienia.

Zwraca wartość prawda, jeśli sam obiekt jest zgodny z wartością. W przeciwnym razie zwróciłaby wartość "", która byłaby zgodna z wartością false.

Tablice używają notacji kątowej.

Kod

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

Problemy

Bez minięciu intial nazwę zmiennej do funkcji, nie możemy przywrócić pełną nazwę zmiennej od początku. Nie mogę wymyślić rozwiązania i będę zaskoczony, jeśli taki był.

Zmienne nazwy ze spacjami są ważne jako klucz do obiektu, podobnie jak inne niepoprawne nazwy zmiennych, to znaczy, że wartość musi być adresowana za pomocą nawiasów trójkątnych. Istnieje kilka rozwiązań, które mogę wymyślić. Regex sprawdza każdą nazwę zmiennej, aby upewnić się, że jest poprawna i stosuje notację nawiasów, jeśli tak nie jest. Nadrzędnym problemem jest to, że reg-ex ma długość strony. Alternatywnie możemy użyć tylko nawiasów trójkątnych, ale nie jest to prawda w stosunku do pierwotnego pytania OP.

Wywołanie indexOf w szukanej tablicy może być nieco ciężkie na bardzo dużych obiektach, ale nie mogę jeszcze wymyślić alternatywy.

Ulepszenia

Oprócz czyszczenia kodu trochę byłoby również miło, jeśli funkcja powrócił tablicę meczów. Podnosi to również inny problem, ponieważ zwrócona tablica nie zawiera odwołań do obiektów rekursywnych. Może funkcja może zaakceptować parametr konfiguracyjny formatu wyniku.

+0

Uruchamiając to na praktycznie dowolnej stronie konsoli firebug, otrzymuję komunikat "Operacja jest niezabezpieczona". Mam kłopoty z niektórymi schematami, ale nie jestem pewien, czy znajdę coś wystarczająco dobrego, żeby tu dodać. Może ktoś inny może coś ulepszyć, żeby to obejść? – eternalnewb

4

To powinno zadziałać. Używa rekurencji, aby osiągnąć wynik.

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

Spraw, aby Twoje rozwiązanie było rekurencyjne. Jeśli masz obiekt, zadzwoń ponownie do swojej funkcji.

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

założę większość przeglądarek trafi ostrzeżenie o zbyt wiele pętli.

+2

Zauważ, że twoja funtja utknęła, używając 'window' jako twojego' obj'. – Ravan

+0

@Ravan: sprawdź moją odpowiedź, która to wyjaśnia. – JCOC611

Powiązane problemy