2010-07-27 8 views
6

Con una sola propiedad esto es bastante fácil:selección profunda dinámica para un objeto de JavaScript


var jsonobj = { 
    "test": "ok" 
} 
var propname = "test"; 
// Will alert "ok" 
alert(jsonobj[propname]); 

Pero lo que yo quiero hacer es utilizar una propiedad anidada:


var jsonobj = { 
    "test": { 
     "test2": "ok" 
    } 
} 
var propname = "test.test2"; 
// Alerts undefined 
alert(jsonobj[propname]); 

¿Hay alguna forma de seleccionando una propiedad anidada "dinámica"? Sé que puedo hacer jsonobj.test.test2, pero el problema es que propname puede cambiar a una propiedad que tiene 1,2 o 3 niveles de profundidad. (Por ejemplo, prueba, test.test2, ...)

+0

¿Se refiere a JSON, o un objeto JavaScript? Ellos no son lo mismo. –

Respuesta

12
function resolve(cur, ns) { 

    var undef; 

    ns = ns.split('.'); 

    while (cur && ns[0]) 
     cur = cur[ns.shift()] || undef; 

    return cur; 

} 

P. ej

// 1: 
resolve({ 
    foo: { bar: 123 } 
}, 'foo.bar'); // => 123 


// 2: 
var complex = { 
    a: { 
     b: [ 
      document.createElement('div') 
     ] 
    } 
}; 

resolve(complex, 'a.b.0.nodeName'); // => DIV 

El beneficio en el uso de esto es que no generará un error si se intenta acceder a algo que no existe - que va a regresar con gracia undefined.


EDIT:

En el comentario, Andy mencionó que esto no generan errores que uno podría esperar que lo haga. Estoy de acuerdo en que obtener undefined es un poco genérico y no hay forma de saber si su valor fue realmente resuelto. Así que, para remediar eso, intente esto:

var resolve = (function(){ 

    var UNRESOLVED = resolve.UNRESOLVED = {}; 
    return resolve; 

    function resolve(cur, ns) { 

     var undef; 

     ns = ns.split('.'); 

     while (cur && ns[0]) 
      cur = cur[ns.shift()] || undef; 

     if (cur === undef || ns[0]) { 
      return UNRESOLVED; 
     } 

     return cur; 

    } 

}()); 

que va a devolver un objeto sin resolver que se puede comprobar de esta manera:

var result = resolve(someObject, 'a.b.c'); 

if (result === resolve.UNRESOLVED) {...} 

No es perfecto, pero es (OMI) la mejor manera para determinar un espacio de nombres sin resolver sin tener que lanzar errores. Si desea que los errores, a continuación, sólo seguir adelante con:

someObject.a.b.c; //... 
+1

Tengo que decir, me gusta bastante. +1 – karim79

+0

Este método funciona bien para mí, ¡muchas gracias! – user403428

+0

+1 ¡Bien hecho! Me gustó la edición 'undefined' también :) –

0

Esto funciona, sino que utiliza suckily eval así que estoy no recomendar su uso:

var jsonobj = { 
    "test": { 
     "test2": "ok" 
    } 
} 
var propname = "test.test2"; 
alert(eval("jsonobj." + propname)); 
​ 

Inténtelo aquí: http://jsfiddle.net/TAgsU/

+0

Aún obtendrá un TypeError si intenta acceder a una propiedad con un valor nulo/indefinido. – James

+0

... además de otras posibles catástrofes a las que podría dar lugar anteriormente.Es por eso que * lo * desaconsejé;) – karim79

1

Puede escribir una pequeña función para dividir la cuerda y luego acceder a cada pieza sucesivamente. Por ejemplo:

function getProperty(propname, object) 
{ 
    var props = propname.split('.'); 
    var obj = object; 
    for (var i=0; i<props.length; i++) 
    { 
     obj = obj[props[i]]; 
    } 
    return obj; 
} 

Obviamente nees un poco de codificación adicional para comprobar si hay objetos nulos, propiedades válidas, etc.

3

Asimismo, sólo implementado esta utilizando una función recursiva interior de esta manera:

function get(obj, ns) {    

    function recurse(o, props) { 
     if (props.length === 0) { 
      return o; 
     } 
     if (!o) { 
      return undefined; 
     } 
     return recurse(o[props.shift()], props); 
    } 

    return recurse(obj, ns.split('.')); 
} 

Esto devolverá el valor profundo de la propiedad especificada por el ns param, de lo contrario siempre regresará indefinido si no existe o si hay algún problema en el camino.

+0

tenga en cuenta que el enfoque recursivo aunque más bonito es más lento que un enfoque iterativo (al menos en mis pruebas) – sym3tri

Cuestiones relacionadas