181 votes

Comment éviter l'erreur "cannot read property of undefined" ?

Dans mon code, je traite un tableau dont certaines entrées contiennent de nombreux objets imbriqués les uns dans les autres, alors que d'autres ne le font pas. Cela ressemble à ce qui suit :

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

Cela me pose des problèmes car j'ai besoin d'itérer dans le tableau à certains moments, et l'incohérence m'envoie des erreurs comme celles-ci :

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);
}

Je suis conscient que je peux dire if(a.b){ console.log(a.b.c)} mais cela est extrêmement fastidieux dans les cas où il y a jusqu'à 5 ou 6 objets imbriqués les uns dans les autres. Existe-t-il un autre moyen (plus simple) de faire en sorte que le fichier console.log soit utilisé UNIQUEMENT s'il existe, sans toutefois déclencher une erreur ?

231voto

str Points 2352

Mise à jour :

  • Si vous utilisez JavaScript conformément à ECMAScript 2020 ou à une version ultérieure, voir chaînage facultatif .
  • TypeScript a ajouté la prise en charge du chaînage facultatif dans la version 3.7 .

    // use it like this obj?.a?.lot?.of?.properties


Solution pour JavaScript avant ECMASCript 2020 ou TypeScript avant la version 3.7 :

Une solution rapide consiste à utiliser une fonction d'aide try/catch avec ES6. fonction de flèche :

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'));

55voto

Benjamin Gruenbaum Points 51406

Ce que vous faites soulève une exception (et à juste titre).

Vous pouvez toujours faire

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

Mais je ne le ferais pas, pensez plutôt à votre cas d'utilisation.

Pourquoi accédez-vous à des données, 6 niveaux imbriqués que vous ne connaissez pas ? Quel cas d'utilisation le justifie ?

En général, vous souhaitez valider le type d'objet auquel vous avez affaire.

Par ailleurs, il convient de ne pas utiliser de déclarations telles que if(a.b) parce qu'il retournera false si a.b est 0 ou même si c'est "0". Vérifiez plutôt si a.b !== undefined

15voto

matt weiss Points 335

Si je comprends bien votre question, vous voulez le moyen le plus sûr de déterminer si un objet contient une propriété.

Le moyen le plus simple est d'utiliser le in opérateur .

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

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

Bien sûr, vous pouvez l'imbriquer aussi profondément que vous le souhaitez.

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

Je ne sais pas si cela peut aider.

14voto

tehwalris Points 90

Si vous utilisez lodash vous pouvez utiliser leur fonction "has". Elle est similaire à la fonction native "in", mais autorise les chemins.

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

14voto

Sean Chen Points 239

Essayez ça. Si a.b est indéfini, il laissera l'option if sans aucune exception.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X