2012-08-24 21 views
7

Digamos que quiero buscar un valor, como 'StackOverflow', en todas las variables declaradas en window. lo puedo hacer con este código:Buscar recursivamente un valor en variables globales y sus propiedades

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

Este código devolverá el nombre de una variable que tiene este valor (o no devuelve nada). Por lo tanto, si he declarado una variable con el valor 'StackOverflow', la encontrará con éxito.

Mi problema es que yo quiero ir más profundo y buscar a través de los objetos window 's (y sus propios objetos anidados) también, para lograr un resultado como este:

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

estoy teniendo problemas con heredada métodos de Objetos. ¿Hay alguna forma de hacer esto?

+0

¿Qué quiere decir con problemas con métodos heredados? –

Respuesta

11

búsqueda profunda pero sin la función recursiva se llama

recursividad funcional tiene límites de pila de memoria interna y desechos.

características adicionales añadidas

Recursive protección de objetos en forma de una matriz buscado; No consume demasiada memoria, por supuesto, ya que los objetos solo se almacenan como referencias.

Devuelve verdadero si el objeto en sí coincide con el valor. De lo contrario, devolvería '' que coincidiría con falso.

Las matrices usan la notación de paréntesis angulares.

El código

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

Problemas

sin pasar el nombre de la variable en la función intial, no podemos devolver el nombre de variable completo desde el principio. No puedo pensar en una solución y me sorprendería si hubiera una.

Los nombres de variable con espacios son válidos como la clave de un objeto, como lo son otros nombres de variable no válidos, simplemente significa que el valor debe abordarse utilizando corchetes angulares. Hay un par de soluciones que puedo pensar. Regex verifica cada nombre de variable para asegurarse de que sea válido y usa la notación de paréntesis angulares si no lo es. El problema principal con esto es que el reg-ex es una página larga. Alternativamente, solo podríamos usar corchetes angulares, pero esto no es realmente cierto para la pregunta original de OP.

La llamada de indexOf en la matriz 'buscado' puede ser un poco pesada en objetos muy grandes, pero todavía no puedo pensar en una alternativa.

Mejoras

Además de limpiar el código un poco, también sería bueno si la función devuelve una matriz de coincidencias. Esto también plantea otro problema en el sentido de que la matriz devuelta no contendría referencias a objetos recursivos. Tal vez la función podría aceptar un parámetro de configuración de formato de resultado.

+0

Al ejecutar esto en prácticamente cualquier página de la consola Firebug, aparece "La operación no es segura". Me estoy metiendo con algunos esquemas de captura de errores, pero no estoy seguro de que encuentre algo lo suficientemente bueno como para agregar aquí. Tal vez alguien más puede hacer una mejora que evita esto? – eternalnewb

4

Esto debería funcionar. Utiliza la recursividad para lograr el resultado.

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

Haga su solución recursiva. Si tiene un objeto, llame de nuevo a su función.

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

Apuesto a que la mayoría de los navegadores recibirán una advertencia por demasiado bucle.

+2

Observe que su funtion se atasca usando 'window' como su' obj'. – Ravan

+0

@Ravan: mira mi respuesta, que explica eso. – JCOC611