¿Cómo puedo evitar los errores ‘no se puede leer la propiedad de undefined’?

6 minutos de lectura

Avatar de usuario de Ari
Ari

En mi código, trato con una matriz que tiene algunas entradas con muchos objetos anidados unos dentro de otros, mientras que otros no. Se parece a lo siguiente:

// Where this array is hundreds of entries long, with a mix
// of the two examples given
var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];

Esto me está dando problemas, porque necesito iterar a través de la matriz a veces, y la inconsistencia me arroja errores como este:

for (i=0; i<test.length; i++) {
    // OK, on i==0, but 'cannot read property of undefined' on i==1
    console.log(a.b.c);
}

Soy consciente de que puedo decir if(a.b){ console.log(a.b.c)}, pero esto es extraordinariamente tedioso en los casos en que hay hasta 5 o 6 objetos anidados unos dentro de otros. ¿Hay alguna otra manera (más fácil) de que pueda tenerlo? solo Hacer el console.log si existe, pero sin tirar un error?

  • El error es probablemente una excepción de Javascript regular, así que pruebe el try..catch declaración. Dicho esto, una matriz que contiene elementos tremendamente heterogéneos me parece un problema de diseño.

    – milimoose

    8 de febrero de 2013 a las 22:17


  • Si su estructura no es consistente en todos los elementos, ¿qué hay de malo en verificar la existencia? De verdad, usaría if ("b" in a && "c" in a.b). Puede ser “tedioso”, pero eso es lo que obtienes por inconsistencia… lógica normal.

    – Ian

    8 de febrero de 2013 a las 22:21

  • ¿Por qué accedería a propiedades que no existen? ¿Por qué no sabe cómo son los objetos?

    – Bergi

    8 de febrero de 2013 a las 22:22

  • Puedo entender por qué alguien no querría que un error colapsara todo. No siempre se puede confiar en que las propiedades de un objeto existan o no existan. Si tiene algo en su lugar que puede manejar el evento de que el objeto tiene un formato incorrecto, entonces su código es mucho más eficiente y menos frágil.

    – SSH Esto

    09/04/2013 a las 20:19

  • Te sorprendería saber cuántos objetos/matrices tienen una forma incorrecta en situaciones de la vida real.

    – Una pregunta más

    8 de septiembre de 2017 a las 2:42

avatar de usuario de str
calle

Actualizar:

  • Si usa JavaScript de acuerdo con ECMAScript 2020 o posterior, consulte encadenamiento opcional.
  • TypeScript ha agregado soporte para encadenamiento opcional en la versión 3.7.
// use it like this
obj?.a?.lot?.of?.properties

Solución para JavaScript anterior a ECMASCript 2020 o TypeScript anterior a la versión 3.7:

Una solución rápida es usar una función auxiliar de prueba/captura con ES6 función de flecha:

function getSafe(fn, defaultVal) {
  try {
    return fn();
  } catch (e) {
    return defaultVal;
  }
}

// use it like this
console.log(getSafe(() => obj.a.lot.of.properties));

// or add an optional default value
console.log(getSafe(() => obj.a.lot.of.properties, 'nothing'));

  • ¡Me encanta! lo único que agregaría es una consola. advertir dentro de la captura, para que sepa del error pero continúa.

    – Rabino Shuki Gur

    11 de diciembre de 2018 a las 10:31

  • Atrapando todo excepciones sin volver a lanzar es maloy, en general, usar excepciones como parte del flujo de ejecución esperado tampoco es excelente, aunque en este caso está bastante bien contenido.

    – hugo

    25 de agosto de 2019 a las 11:28

  • ¡Oh hombre, ahora eres mi héroe! try and catch lo hizo por mí después de todos mis esfuerzos fallidos con Object.assign, el operador ‘OR’, el operador ternario, etc., nada funciona en presencia de un error indefinido. ¡¡Gracias!!

    usuario7622147

    11 de febrero de 2022 a las 15:11

Avatar de usuario de Benjamin Gruenbaum
benjamin grünbaum

Lo que está haciendo plantea una excepción (y con razón). Siempre puedes hacer:

try{
   window.a.b.c
}catch(e){
   console.log("YO",e)
}

Pero no lo haría, en lugar de eso, piense en su caso de uso.

¿Por qué está accediendo a datos, 6 niveles anidados que no conoce? ¿Qué caso de uso justifica esto?

Por lo general, le gustaría validar con qué tipo de objeto está tratando.

Además, en una nota al margen, no debe usar declaraciones como if(a.b) porque devolverá falso si ab es 0 o incluso si es “0”. En su lugar, compruebe si a.b !== undefined

  • Con respecto a su primera edición: está justificada; Estoy tratando con entradas de bases de datos estructuradas JSON, de modo que los objetos escalarán múltiples niveles de campos (es decir, entradas.usuarios.mensajes.fecha, etc., donde no todos los casos tienen datos ingresados)

    – Ari

    8 de febrero de 2013 a las 22:23

  • “devolverá verdadero si ab es 0” – no. typeof a.b === "undefined" && a.b!=null – no es necesario hacer la segunda parte después de la primera, y tiene más sentido simplemente hacer if ("b" in a)

    – Ian

    8 de febrero de 2013 a las 22:23


  • @Ian, sí, obviamente lo dije en serio al revés, devolverá falso incluso si ab es “0”. Buena atrapada

    – Benjamin Grünbaum

    8 de febrero de 2013 a las 22:24

  • @BenjaminGruenbaum Suena bien, no estaba seguro de si lo decía en serio. Además, creo que quieres typeof a.b !== “indefinido” && ab!=null` – observe el !==

    – Ian

    8 de febrero de 2013 a las 22:26

  • Si no quiere aburrirse de ab && abc && console.log(abc), entonces esta es la única manera de registrar incógnitas consistentemente.

    – Brian Cray

    08/02/2013 a las 22:31

avatar de usuario de matt weiss
matt weiss

Si entiendo su pregunta correctamente, desea la forma más segura de determinar si un objeto contiene una propiedad.

La forma más fácil es usar el in operador.

window.a = "aString";
//window should have 'a' property
//lets test if it exists
if ("a" in window){
    //true
 }

if ("b" in window){
     //false
 }

Por supuesto, puedes anidar esto tan profundo como quieras.

if ("a" in window.b.c) { }

No estoy seguro si esto ayuda.

  • No puedes anidar esto con seguridad tan profundamente como quieras. Y si window.b ¿es indefinido? Obtendrá un error de tipo: Cannot use 'in' operator to search for 'c' in undefined

    – Trevor

    28 de agosto de 2017 a las 23:34


Avatar de usuario de Sean Chen
sean chen

Prueba esto. Si a.b es undefineddejará el if declaración sin ninguna excepción.

if (a.b && a.b.c) {
  console.log(a.b.c);
}

avatar de usuario de tehwalris
tehwalris

Si estás usando lodashpodrías usar su has función. Es similar al nativo “in”, pero permite caminos.

var testObject = {a: {b: {c: 'walrus'}}};
if(_.has(testObject, 'a.b.c')) {
  //Safely access your walrus here
}

  • Mejor, podemos usar _.get() con predeterminado para fácil lectura: _.get(object, 'a.b.c', 'default');

    – Si no

    18 de junio de 2018 a las 13:53


Avatar de usuario de Peter Mortensen
Pedro Mortensen

Si utiliza Babelya puede usar la sintaxis de encadenamiento opcional con @babel/plugin-proposal-opcional-encadenamiento Complemento de Babel. Esto le permitiría reemplazar esto:

console.log(a && a.b && a.b.c);

con este:

console.log(a?.b?.c);

  • Mejor, podemos usar _.get() con predeterminado para fácil lectura: _.get(object, 'a.b.c', 'default');

    – Si no

    18 de junio de 2018 a las 13:53


Avatar de usuario de Peter Mortensen
Pedro Mortensen

Si usted tiene Lodashpuedes usar su .get método:

_.get(a, 'b.c.d.e')

O darle un valor predeterminado:

_.get(a, 'b.c.d.e', default)

  • Hola, ¿eso también puede capturar la propiedad de error nulo?

    – Jovylle

    7 abr 2022 a las 16:22

¿Ha sido útil esta solución?