2012-01-11 10 views
48

Duplicar posible:
Accessing nested JavaScript objects with string keyJavascript: Obtener valor de profundidad del objeto al pasar camino a ella como cadena

Tal vez el título no es lo suficientemente claro, sólo que no sabía cómo para especificar lo que estoy buscando y mi inglés es realmente malo, lo siento.

Estoy tratando de crear una función que devuelva el valor del objeto, pero también se juega bien con los objetos anidados. Por ejemplo:

var obj = { 
    foo: { bar: 'baz' } 
}; 

Quiero acceder al valor de obj.foo.bar por abastecer la cadena "foo.bar" a la función.

function(obj, path) { 
    // Path can be "foo.bar", or just "foo". 
} 

¡Gracias!

+0

Esto es ahora compatible con el uso de lodash _.get (obj, propiedad). Consulte https://lodash.com/docs#get –

+0

Dado que esta pregunta se marcó como duplicada (incluso no lo es), tengo que responder en un comentario. Puede usar ECMAScript6 Destructuring: 'var obj = {foo: {bar: 'baz'}}; ({foo: {bar: value}} = obj); console.log (value);' – Alexander

Respuesta

37

Considere esto:

var obj = { 
    foo: { bar: 'baz' } 
}; 

function deepFind(obj, path) { 
    var paths = path.split('.') 
    , current = obj 
    , i; 

    for (i = 0; i < paths.length; ++i) { 
    if (current[paths[i]] == undefined) { 
     return undefined; 
    } else { 
     current = current[paths[i]]; 
    } 
    } 
    return current; 
} 

console.log(deepFind(obj, 'foo.bar')) 
+5

@ 7elephant y qiao: falla (arroja un error) si alguna parte de la ruta evalúa ' null'. Eso podría ser una característica o un error, según tu punto de vista. :-) –

3

Desea dividir la cadena en el punto y luego indexar repetidamente en el objeto, p. a lo largo de las líneas de:

function goDeep(obj, path) { 
    var parts = path.split('.'), 
     rv, 
     index; 
    for (rv = obj, index = 0; rv && index < parts.length; ++index) { 
     rv = rv[parts[index]]; 
    } 
    return rv; 
} 

Live example

que funciona porque se puede acceder a la propiedad de un objeto en un par de maneras diferentes: Hay sintaxis de puntos utilizando un literal (obj.foo), y hay entre corchetes sintaxis utilizando una cadena (obj["foo"]). En el último caso, la cadena puede ser el resultado de cualquier expresión, no tiene que ser una cadena literal. En en todo el, rv se establece en el mismo valor:

rv = obj.foo.bar; 
// Or 
rv = obj.foo["bar"]; 
// Or 
f = "foo"; 
rv = obj[f].bar; 
// Or 
s = "b"; 
rv = obj.foo[s + "ar"]; 
+1

Seguramente, el requisito era no expresado, pero ¿no podríamos sospechar que OP también podría querer una llamada a función tal como 'goDeep (myObj, 'bar [3] .baz')'? Eso puede estar fuera del alcance de la pregunta actual ... –

+1

@DavidHedlund: punto adecuado, puede ser útil verificar la forma entre corchetes dentro de cada 'parte' para que sea totalmente compatible con la propia sintaxis de JavaScript.Lo dejo como un ejercicio para el OP. :-) –

+0

(Bueno, no * completamente *, para hacer eso, básicamente, debes volver a inventar [o -shudder- use] 'eval'. Pero decir, en su mayoría compatible con.) –

5

algo como:

function(obj, path) { 
    var current=obj; 
    path.split('.').forEach(function(p){ current = current[p]; }); 
    return current; 
} 
+0

http://meta.stackexchange.com/a/118023/134069 –

58

Esto funciona correctamente:

var deep_value = function(obj, path){ 
    for (var i=0, path=path.split('.'), len=path.length; i<len; i++){ 
     obj = obj[path[i]]; 
    }; 
    return obj; 
}; 

Aquí está el profesional de/demo: jsfiddle.net/tadeck/5Pt2q/13/

EDITAR: He eliminado variables redundantes, acortado el código.

+1

hermosa. mejor que nada en el duplicado http://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-with-string-key –

+0

extended for array support. http://jsfiddle.net/5Pt2q/20/ –

+3

@SteveBlack mejor cómo? Admite una sintaxis más restringida y no tiene errores al verificar si se intenta resolver una clave que no existe. – Alnitak

7

¿Quiere decir algo como esto? Es una versión recursiva

function recLookup(obj, path) { 
    parts = path.split("."); 
    if (parts.length==1){ 
     return obj[parts[0]]; 
    } 
    return recLookup(obj[parts[0]], parts.slice(1).join(".")); 
} 

Ver http://jsfiddle.net/kExSr/

+0

¡ORO! Pude usar esto para mapear una ruta/Root [1]/This/working a un objeto {"Root [1]": This {working: "value"}}. tuvo que recortar el/y el cambio. a/pero por lo demás hermoso. –

+1

esto no parece demasiado rápido. No debería unir() las rutas de nuevo, simplemente verifique si path es una cadena o una matriz – Jonathan

Cuestiones relacionadas