Si tengo una referencia a un objeto:
var test = {};
que potencialmente (pero no inmediatamente) tendrá objetos anidados, algo como:
{level1: {level2: {level3: "level3"}}};
¿Cuál es la mejor manera de verificar la existencia de propiedades en objetos profundamente anidados?
alert(test.level1);cede undefined, pero alert(test.level1.level2.level3);falla.
Actualmente estoy haciendo algo como esto:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
pero me preguntaba si hay una mejor manera.
javascript
object
properties
nested
usuario113716
fuente
fuente

Respuestas:
Tienes que hacerlo paso a paso si no quieres un
TypeErrorporque si uno de los miembros esnulloundefined, e intentas acceder a un miembro, se lanzará una excepción.Puede simplemente
catchla excepción, o hacer una función para probar la existencia de múltiples niveles, algo como esto:ACTUALIZACIÓN ES6:
Aquí hay una versión más corta de la función original, que usa las funciones y la recursión de ES6 (también está en forma de cola ):
Sin embargo, si desea obtener el valor de una propiedad anidada y no solo verificar su existencia, aquí hay una función simple de una línea:
La función anterior le permite obtener el valor de las propiedades anidadas, de lo contrario volverá
undefined.ACTUALIZACIÓN 2019-10-17:
La propuesta de encadenamiento opcional alcanzó la Etapa 3 en el proceso del comité ECMAScript , esto le permitirá acceder de manera segura a propiedades profundamente anidadas, utilizando el token
?., el nuevo operador de encadenamiento opcional :Si alguno de los niveles accedidos es
nulloundefinedla expresión se resolveráundefinedpor sí misma.La propuesta también le permite manejar llamadas a métodos de manera segura:
La expresión anterior producirá
undefinedifobj,obj.level1orobj.level1.methodarenulloundefined, de lo contrario, llamará a la función.Puedes comenzar a jugar con esta función con Babel usando el complemento de encadenamiento opcional .Desde Babel 7.8.0 , ES2020 es compatible por defecto
Verifique este ejemplo en el REPL de Babel.
🎉🎉 ACTUALIZACIÓN: diciembre de 2019 🎉🎉
La propuesta de encadenamiento opcional finalmente alcanzó la Etapa 4 en la reunión de diciembre de 2019 del comité TC39. Esto significa que esta característica será parte del Estándar ECMAScript 2020 .
fuente
argumentsEn realidad no es una matriz.Array.prototype.slice.call(arguments)lo convierte en una matriz formal. Aprendervar obj = arguments[0];y comenzar desde envar i = 1lugar de copiar elargumentsobjetoargsdeclaración de variable se puede eliminar y...argsse puede utilizar como el segundo argumento para elcheckNestedmétodo. developer.mozilla.org/en/docs/Web/JavaScript/Reference/…Aquí hay un patrón que tomé de Oliver Steele :
De hecho, todo el artículo es una discusión sobre cómo puede hacer esto en javascript. Él decide usar la sintaxis anterior (que no es tan difícil de leer una vez que te acostumbras) como idioma.
fuente
(test || {})es que si la prueba no está definida, entonces lo estás haciendo({}.level1 || {}). Por supuesto,{}.level1no está definido, lo que significa que lo estás haciendo{}.level2, y así sucesivamente.testno se declara, habrá un Error de referencia , pero eso no es un problema, porque si no se declara, hay un error que corregir, por lo que el error es algo bueno.if(test.level1 && test.level1.level2 && test.level1.level2.level3)Actualizar
Parece que lodash ha agregado
_.gettodas sus necesidades de obtención de propiedades anidadas.https://lodash.com/docs#get
Respuesta anterior
Los usuarios de lodash pueden disfrutar de lodash.contrib que tiene un par de métodos que mitigan este problema .
getPath
Firma:
_.getPath(obj:Object, ks:String|Array)Obtiene el valor a cualquier profundidad en un objeto anidado en función de la ruta descrita por las claves proporcionadas. Las claves se pueden dar como una matriz o como una cadena separada por puntos. Devuelve
undefinedsi no se puede llegar a la ruta.fuente
function isPathDefined(object, path) { return typeof _.getPath(object, path) !== 'undefined'; }_.get(countries, 'greece.sparta.playwright', 'default'); // → 'default' _.has(countries, 'greece.spart.playwright') // → falsevar url = _.get(e, 'currentTarget.myurl', null) || _.get(e, 'currentTarget.attributes.myurl.nodeValue', null) || nullHe realizado pruebas de rendimiento (gracias cdMinix por agregar lodash) en algunas de las sugerencias propuestas para esta pregunta con los resultados que se enumeran a continuación.
Envoltura de objetos (por Oliver Steele) - 34% - más rápido
Solución original (sugerida en la pregunta) - 45%
checkNested - 50%
get_if_exist - 52%
Cadena válida - 54%
objHasKeys - 63%
nestedPropertyExists - 69%
_.get - 72%
más profundo - 86%
payasos tristes - 100% - más lento
fuente
_.get()? ¿Cuán eficiente es en comparación con esas respuestas?reduceotry/catchpor conveniencia.try { test.level1.level2.level3 } catch (e) { // some logger e }Usted puede leer una propiedad de objeto a cualquier profundidad, si se maneja el nombre como una cadena:
't.level1.level2.level3'.Regresa
undefinedsi alguno de los segmentos esundefined.fuente
Si está codificando en el entorno ES6 (o utilizando 6to5 ), puede aprovechar la sintaxis de la función de flecha :
Con respecto al rendimiento, no hay penalización de rendimiento por usar el
try..catchbloque si se establece la propiedad. Hay un impacto en el rendimiento si la propiedad no está configurada.Considere simplemente usar
_.has:fuente
try-catchenfoque es la mejor respuesta. Hay una diferencia filosófica entre consultar un objeto por su tipo, y asumir que la API existe y fallar en consecuencia si no es así. Este último es más apropiado en lenguajes poco escritos. Ver stackoverflow.com/a/408305/2419669 . Eltry-catchenfoque también es mucho más claro queif (foo && foo.bar && foo.bar.baz && foo.bar.baz.qux) { ... }.qué tal si
fuente
hasOwnProperty()n veces?Respuesta ES6, probada a fondo :)
→ ver Codepen con cobertura de prueba completa
fuente
===Comparo explícitamente las diferentes falsificaciones y la prueba agregada. Si tiene una idea mejor, hágamelo saber).false. Y luego es posible que desee tener un valor en su objeto establecido enundefined(Sé que es extraño pero es JS). Hice un valor falso positivo establecido en'Prop not Found':const hasTruthyProp = prop => prop === 'Prop not found' ? false : true const path = obj => path => path.reduce((obj, prop) => { return obj && obj.hasOwnProperty(prop) ? obj[prop] : 'Prop not found' }, obj) const myFunc = compose(hasTruthyProp, path(obj))También puede usar la propuesta de encadenamiento opcional tc39 junto con babel 7 - tc39-request-optional-chaining
El código se vería así:
fuente
Intenté un enfoque recursivo:
Se
! keys.length ||inicia la recursión para que no ejecute la función sin teclas para probar. Pruebas:Lo estoy usando para imprimir una vista html amigable de un grupo de objetos con clave / valores desconocidos, por ejemplo:
fuente
Creo que el siguiente script ofrece una representación más legible.
declarar una función:
luego úsalo así:
Lo llamo "técnica de payaso triste" porque está usando el signo o (
EDITAR:
Aquí hay una versión para TypeScript
da verificaciones de tipo en tiempo de compilación (así como el intellisense si usa una herramienta como Visual Studio)
El uso es el mismo:
pero esta vez intellisense funciona!
Además, puede establecer un valor predeterminado:
fuente
°0o <°(())))><Objecttipo. +1.crear un proyecto global
functiony utilizarlo en todoprueba esto
si condición
fuente
Una forma simple es esta:
El
try/catchatrapa los casos de cuando cualquiera de la mayor nivel objetos tales como prueba, test.level1, test.level1.level2 no están definidas.fuente
No vi ningún ejemplo de alguien usando Proxies
Entonces se me ocurrió el mío. Lo bueno de esto es que no tienes que interpolar cadenas. En realidad, puede devolver una función de
objeto encadena y hacer algunas cosas mágicas con ella. Incluso puede llamar a funciones y obtener índices de matriz para buscar objetos profundosMostrar fragmento de código
El código anterior funciona bien para cosas sincrónicas. Pero, ¿cómo probarías algo que es asíncrono como esta llamada ajax? ¿Cómo se prueba eso? ¿Qué pasa si la respuesta no es json cuando devuelve un error 500 http?
Asegúrese de que puede usar async / wait para deshacerse de algunas devoluciones de llamada. Pero, ¿y si pudieras hacerlo aún más mágicamente? algo que se parece a esto:
Probablemente se pregunte dónde están todas las promesas y
.thencadenas ... esto podría estar bloqueando todo lo que sabe ... pero usando la misma técnica de Proxy con promesa, puede probar la existencia de una ruta compleja profundamente anidada sin escribir una sola funciónMostrar fragmento de código
fuente
En base a esta respuesta , se me ocurrió esta función genérica usando la
ES2015cual resolvería el problemafuente
function validChain (object, path) { return path.split('.').reduce((a, b) => (a || { })[b], object) !== undefined }He creado una pequeña función para obtener propiedades de objetos anidados de forma segura.
O una versión más simple pero ligeramente ilegible:
O incluso más corto pero sin recurrir a la bandera falsa:
Tengo prueba con:
Y aquí hay algunas pruebas:
Para ver todo el código con la documentación y las pruebas que he probado, puede consultar mi github gist: https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues-js
fuente
Una versión ES5 más corta de la excelente respuesta de @ CMS:
Con una prueba similar:
fuente
checkObjHasKeys(test, ['level1', 'level2', 'asdf', 'asdf']);success = false;areturn false. Debería rescatar una vez que sepa que se rompe, nada más profundo puede existir una vez que sea nulo o indefinido. Esto evitaría los errores en los elementos anidados más profundos, ya que obviamente tampoco existen.Creo que esta es una ligera mejora (se convierte en 1 línea):
Esto funciona porque el operador && devuelve el operando final que evaluó (y cortocircuita).
fuente
Estaba buscando el valor que se devolvería si la propiedad existe, así que modifiqué la respuesta de CMS anterior. Esto es lo que se me ocurrió:
fuente
La respuesta dada por CMS funciona bien con la siguiente modificación para cheques nulos también
fuente
Las siguientes opciones se elaboraron a partir de esta respuesta . Mismo árbol para ambos:
Dejar de buscar cuando no esté definido
Asegure cada nivel uno por uno
fuente
Sé que esta pregunta es antigua, pero quería ofrecer una extensión agregando esto a todos los objetos. Sé que las personas tienden a fruncir el ceño al usar el prototipo de Objeto para la funcionalidad de objetos extendidos, pero no encuentro nada más fácil que hacerlo. Además, ahora está permitido con el método Object.defineProperty .
Ahora, para probar cualquier propiedad en cualquier objeto, simplemente puede hacer:
Aquí hay un jsfiddle para probarlo, y en particular incluye algo de jQuery que se rompe si modifica el Object.prototype directamente debido a que la propiedad se vuelve enumerable. Esto debería funcionar bien con bibliotecas de terceros.
fuente
Esto funciona con todos los objetos y matrices :)
ex:
esta es mi versión mejorada de la respuesta de Brian
Utilicé _has como el nombre de la propiedad porque puede entrar en conflicto con la propiedad has existente (ej .: mapas)
Aquí está el violín
fuente
Aquí está mi opinión: la mayoría de estas soluciones ignoran el caso de una matriz anidada como en:
Es posible que desee verificar
obj.l2[0].kCon la función a continuación, puedes hacer
deeptest('l2[0].k',obj)La función devolverá verdadero si el objeto existe, falso de lo contrario
fuente
Ahora también podemos usar
reducepara recorrer las claves anidadas:fuente
Puede hacer esto usando la función recursiva. Esto funcionará incluso si no conoce el nombre de todas las claves de objeto anidadas.
fuente
Hay una función aquí en thecodeabode (safeRead) que hará esto de manera segura ... es decir
si alguna propiedad es nula o indefinida, se devuelve una cadena vacía
fuente
Según un comentario anterior , aquí hay otra versión en la que tampoco se pudo definir el objeto principal:
fuente
Escribí mi propia función que toma la ruta deseada y tiene una función de devolución de llamada buena y mala.
Uso:
fuente
fuente