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
TypeError
porque si uno de los miembros esnull
oundefined
, e intentas acceder a un miembro, se lanzará una excepción.Puede simplemente
catch
la 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
null
oundefined
la expresión se resolveráundefined
por sí misma.La propuesta también le permite manejar llamadas a métodos de manera segura:
La expresión anterior producirá
undefined
ifobj
,obj.level1
orobj.level1.method
arenull
oundefined
, 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
arguments
En 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 = 1
lugar de copiar elarguments
objetoargs
declaración de variable se puede eliminar y...args
se puede utilizar como el segundo argumento para elcheckNested
mé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,{}.level1
no está definido, lo que significa que lo estás haciendo{}.level2
, y así sucesivamente.test
no 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
_.get
todas 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
undefined
si 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') // → false
var url = _.get(e, 'currentTarget.myurl', null) || _.get(e, 'currentTarget.attributes.myurl.nodeValue', null) || null
He 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?reduce
otry/catch
por 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
undefined
si 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..catch
bloque si se establece la propiedad. Hay un impacto en el rendimiento si la propiedad no está configurada.Considere simplemente usar
_.has
:fuente
try-catch
enfoque 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-catch
enfoque 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 <°(())))><
Object
tipo. +1.crear un proyecto global
function
y utilizarlo en todoprueba esto
si condición
fuente
Una forma simple es esta:
El
try/catch
atrapa 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
.then
cadenas ... 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
ES2015
cual 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].k
Con 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
reduce
para 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