Dado un objeto JS
var obj = { a: { b: '1', c: '2' } }
y una cuerda
"a.b"
¿Cómo puedo convertir la cadena a notación de puntos para que pueda ir
var val = obj.a.b
Si la cadena fuera justa 'a'
, podría usarla obj[a]
. Pero esto es más complejo. Me imagino que hay un método sencillo pero se escapa en la actualidad.
javascript
nevf
fuente
fuente
eval
es malvado; no lo useRespuestas:
Aquí hay un elegante one-liner que es 10 veces más corto que las otras soluciones:
[editar] O en ECMAScript 6:
(No es que piense que eval siempre es malo como otros sugieren que es (aunque generalmente lo es), sin embargo, esas personas estarán complacidas de que este método no use eval. Lo anterior encontrará
obj.a.b.etc
dadoobj
y la cadena"a.b.etc"
).En respuesta a aquellos que todavía tienen miedo de usar a
reduce
pesar de estar en el estándar ECMA-262 (5a edición), aquí hay una implementación recursiva de dos líneas:Dependiendo de las optimizaciones que esté haciendo el compilador JS, es posible que desee asegurarse de que las funciones anidadas no se redefinan en cada llamada a través de los métodos habituales (colocándolas en un cierre, objeto o espacio de nombres global).
editar :
Para responder una pregunta interesante en los comentarios:
(nota al margen: lamentablemente no puede devolver un objeto con un Setter, ya que eso violaría la convención de llamada; el comentarista parece referirse a una función general de estilo setter con efectos secundarios como
index(obj,"a.b.etc", value)
hacerobj.a.b.etc = value
).El
reduce
estilo no es realmente adecuado para eso, pero podemos modificar la implementación recursiva:Manifestación:
... aunque personalmente recomendaría hacer una función separada
setIndex(...)
. Me gustaría terminar con una nota al margen de que el autor original de la pregunta podría (¿debería?) Estar trabajando con conjuntos de índices (que pueden obtener.split
), en lugar de cadenas; aunque generalmente no hay nada malo con una función de conveniencia.Un comentarista preguntó:
Javascript es un lenguaje muy extraño; en general, los objetos solo pueden tener cadenas como sus claves de propiedad, por lo que, por ejemplo, si
x
fuera un objeto genérico comox={}
, entoncesx[1]
se convertiría enx["1"]
... usted lo leyó bien ... sí ...Las matrices de Javascript (que son en sí mismas instancias de Object) fomentan específicamente las claves enteras, aunque podría hacer algo como
x=[]; x["puppy"]=5;
.Pero en general (y hay excepciones),
x["somestring"]===x.somestring
(cuando está permitido; no se puede hacerx.123
).(Tenga en cuenta que cualquier compilador JS que esté usando podría elegir, tal vez, compilarlos en representaciones más sensatas si puede probar que no violaría la especificación).
Entonces, la respuesta a su pregunta dependerá de si está asumiendo que esos objetos solo aceptan enteros (debido a una restricción en su dominio problemático), o no. Asumamos que no. Entonces, una expresión válida es una concatenación de un identificador base más algunos
.identifier
s más algunos["stringindex"]
sEsto sería equivalente a
a["b"][4]["c"]["d"][1][2][3]
, aunque probablemente también deberíamos apoyarloa.b["c\"validjsstringliteral"][3]
. Tendría que consultar la sección de gramática ecmascript en literales de cadena para ver cómo analizar un literal de cadena válido. Técnicamente, también querría verificar (a diferencia de mi primera respuesta) quea
es un identificador de JavaScript válido .Una respuesta simple a su pregunta, sin embargo, si sus cadenas no contienen comas o soportes , sería apenas sea para que coincida con la longitud 1+ secuencias de caracteres no en el conjunto
,
o[
o]
:Si sus cadenas no contienen caracteres de escape o
"
caracteres , y debido a que IdentifierNames es un sublenguaje de StringLiterals (creo que ???), primero puede convertir sus puntos a []:Por supuesto, siempre tenga cuidado y nunca confíe en sus datos. Algunas formas malas de hacer esto que podrían funcionar para algunos casos de uso también incluyen:
Edición especial 2018:
Hagamos un círculo completo y hagamos la solución más ineficiente y terriblemente sobreprogramada que podamos encontrar ... en interés del servicio de
purezasintáctica . ¡Con objetos Proxy ES6! ... Definamos también algunas propiedades que (aunque son buenas y maravillosas) pueden romper bibliotecas mal escritas. Tal vez debería desconfiar de usar esto si le preocupa el rendimiento, la cordura (la suya o la de los demás), su trabajo, etc.Manifestación:
Salida:
idea ineficiente: puede modificar lo anterior para despachar en función del argumento de entrada; use el
.match(/[^\]\[.]+/g)
método para admitirobj['keys'].like[3]['this']
, o siinstanceof Array
, simplemente acepte una matriz como entrada comokeys = ['a','b','c']; obj.H[keys]
.Por sugerencia de que tal vez desee manejar índices indefinidos de una manera 'más suave' al estilo NaN (por ejemplo,
index({a:{b:{c:...}}}, 'a.x.c')
devolver Indefinido en lugar de no detectado TypeError) ...:1) Esto tiene sentido desde la perspectiva de "deberíamos regresar indefinido en lugar de arrojar un error" en la situación del índice unidimensional ({}) ['eg'] == undefined, entonces "deberíamos regresar indefinido en lugar de arrojar un error "en la situación N-dimensional.
2) Esto no tiene sentido desde la perspectiva que estamos haciendo
x['a']['x']['c']
, lo que fallaría con un TypeError en el ejemplo anterior.Dicho esto, haría que esto funcionara reemplazando su función reductora con:
(o,i)=>o===undefined?undefined:o[i]
O(o,i)=>(o||{})[i]
.(Puede hacer esto más eficiente usando un bucle for y rompiendo / regresando cada vez que el resultado secundario en el que se indexará a continuación no esté definido, o usando un try-catch si espera que tales fallas sean lo suficientemente raras).
fuente
reduce
no es compatible con todos los navegadores utilizados actualmente.Array.reduce
es parte del estándar ECMA-262. Si realmente desea admitir navegadores obsoletos, puede definirArray.prototype.reduce
la implementación de muestra dada en algún lugar (por ejemplo, developer.mozilla.org/en/JavaScript/Reference/Global_Objects/… ).var setget = function( obj, path ){ function index( robj,i ) {return robj[i]}; return path.split('.').reduce( index, obj ); }
Si puede usar lodash , hay una función que hace exactamente eso:
_.get (objeto, ruta, [valor predeterminado])
fuente
_.get(object, path)
no se rompe si no se encontró una ruta.'a.b.etc'.split('.').reduce((o,i)=>o[i], obj)
hace. Para mi caso específico, no para cada caso, exactamente lo que necesitaba. ¡Gracias!defaultValue
. El_.get()
método devuelve el valor predeterminado si se_.get()
resuelveundefined
, así que configúrelo en lo que desee y observe el valor que configuró._.set(object, path, value)
.Un ejemplo un poco más complicado con la recursividad.
fuente
también puedes usar lodash.get
Simplemente instale este paquete (npm i --save lodash.get) y luego utilícelo así:
fuente
Si espera desreferenciar la misma ruta muchas veces, crear una función para cada ruta de notación de puntos en realidad tiene el mejor rendimiento con diferencia (expandiendo las pruebas de rendimiento a las que James Wilkins se vincula en los comentarios anteriores).
El uso del constructor de funciones tiene algunos de los mismos inconvenientes que eval () en términos de seguridad y el peor de los casos, pero IMO es una herramienta mal utilizada para casos en los que necesita una combinación de dinamismo extremo y alto rendimiento. Utilizo esta metodología para construir funciones de filtro de matriz y llamarlas dentro de un bucle de resumen AngularJS. Mis perfiles muestran consistentemente el paso array.filter () que toma menos de 1 ms para desreferenciar y filtrar alrededor de 2000 objetos complejos, utilizando rutas definidas dinámicamente de 3 a 4 niveles de profundidad.
Una metodología similar podría usarse para crear funciones de establecimiento, por supuesto:
fuente
Muchos años desde la publicación original. Ahora hay una gran biblioteca llamada 'ruta de objeto'. https://github.com/mariocasciaro/object-path
Disponible en NPM y BOWER https://www.npmjs.com/package/object-path
Es tan fácil como:
Y funciona para propiedades y matrices profundamente anidadas.
fuente
Sugiero dividir el camino e iterarlo y reducir el objeto que tiene. Esta propuesta funciona con un valor predeterminado para las propiedades faltantes.
fuente
Tenga en cuenta que si ya está usando Lodash , puede usar las funciones
property
oget
:El subrayado también tiene una
property
función, pero no admite la notación de puntos.fuente
Otras propuestas son un poco crípticas, así que pensé que contribuiría:
fuente
Puede usar la biblioteca disponible en npm, lo que simplifica este proceso. https://www.npmjs.com/package/dot-object
fuente
Esto es mucho código en comparación con la forma mucho más simple
eval
de hacerlo, pero como dice Simon Willison, nunca debes usar eval .Además, JSFiddle .
fuente
He extendido la respuesta elegante de ninjagecko para que la función maneje las referencias de estilo punteadas y / o de matriz, y para que una cadena vacía haga que se devuelva el objeto padre.
Aqui tienes:
Vea mi ejemplo de trabajo jsFiddle aquí: http://jsfiddle.net/sc0ttyd/q7zyd/
fuente
[]
notación es siempre para matrices. también puede haber claves de objeto representadas de esa manera, por ejemplo.obj['some-problem/name'].list[1]
Para solucionar esto, tuve que actualizar unaarr_deref
función como estajavascript function arr_deref(o, ref, i) { return !ref ? o : (o[(ref.slice(0, i ? -1 : ref.length)).replace(/^['"]|['"]$/g, '')]); }
fuente
Puede obtener el valor de un miembro de objeto mediante notación de puntos con una sola línea de código:
En tu caso:
Para hacerlo simple, puede escribir una función como esta:
Explicación:
El constructor de funciones crea un nuevo objeto de función. En JavaScript, cada función es en realidad un objeto Función. La sintaxis para crear una función explícitamente con el constructor de funciones es:
donde
arguments(arg1 to argN)
debe ser una cadena que corresponda a un identificador javaScript válido yfunctionBody
es una cadena que contiene las declaraciones javaScript que comprenden la definición de la función.En nuestro caso, aprovechamos el cuerpo de la función de cadena para recuperar el miembro del objeto con notación de puntos.
Espero eso ayude.
fuente
Respuesta GET / SET que también funciona en react native (no se puede asignar a
Object.prototype
actualmente):Uso:
fuente
Copié lo siguiente de la respuesta de Ricardo Tomasi y modifiqué para crear también subobjetos que aún no existen según sea necesario. Es un poco menos eficiente (más
if
s y creación de objetos vacíos), pero debería ser bastante bueno.Además, nos permitirá hacer
Object.prop(obj, 'a.b', false)
donde antes no podíamos. Desafortunadamente, todavía no nos deja asignarundefined
... No estoy seguro de cómo hacerlo todavía.fuente
Si desea convertir cualquier objeto que contenga claves de notación de puntos en una versión ordenada de esas claves, puede usar esto.
Esto convertirá algo como
a
fuente
Aquí está mi código sin usar
eval
. También es fácil de entender.fuente
Sí, se le preguntó hace 4 años y sí, extender prototipos base no suele ser una buena idea, pero si mantiene todas las extensiones en un solo lugar, podrían ser útiles.
Entonces, aquí está mi manera de hacer esto.
Ahora podrá obtener propiedades anidadas en todas partes sin importar el módulo con la función o la función copiar / pegar.
UPD Ejemplo:
UPD 2. La siguiente extensión rompe la mangosta en mi proyecto. También he leído que podría romper jquery. Entonces, nunca lo hagas de la siguiente manera
fuente
Aquí está mi implementación
Implementación 1
Implementación 2 (usando la reducción de matriz en lugar de la división)
Ejemplos:
También puede manejar objetos dentro de matrices como para
fuente
Esta es mi solución extendida propuesta por: ninjagecko
Para mí, la notación de cadena simple no era suficiente, por lo que la siguiente versión admite cosas como:
index (obj, 'data.accounts [0] .address [0] .postcode');
fuente
A riesgo de vencer a un caballo muerto ... Esto me resulta muy útil al atravesar objetos anidados para hacer referencia a dónde se encuentra con respecto al objeto base o un objeto similar con la misma estructura. Para ese fin, esto es útil con una función transversal de objeto anidado. Tenga en cuenta que he usado una matriz para mantener la ruta. Sería trivial modificar esto para usar una ruta de cadena o una matriz. También tenga en cuenta que puede asignar "indefinido" al valor, a diferencia de algunas de las otras implementaciones.
fuente
Usé este código en mi proyecto
Uso:
fuente
Pocos años después, encontré esto que maneja el alcance y la matriz. p.ej
a['b']["c"].d.etc
fuente
No está claro cuál es tu pregunta. Dado su objeto,
obj.a.b
le daría "2" tal como es. Si desea manipular la cadena para utilizar corchetes, puede hacer esto:fuente
a.b.c
y realmente no logra lo que quieren ... Quieren el valor, no uneval
camino.a.b.c
, pero tienes razón, aparentemente quería obtener / establecer el valor de la propiedad enobj.a.b
. La pregunta fue confusa para mí, ya que dijo que quería "convertir la cadena" ...aquí están mis 10 centavos por caja, la función de abajo se obtendrá / establecerá en función de la ruta proporcionada, .. seguro de que puede mejorarla, elimine || y reemplácelo con
Object.hasOwnProperty
si le importan los valores falsos por error,Lo probé con
a.b.c
y ab2.c{a:{b:[0,1,{c:7}]}}
y funciona tanto para configurar como para obtener :).cheerz
fuente