Come evitare errori “non può leggere la proprietà di non definito”?

Nel mio codice, mi occupo di un array che ha alcune voci con molti oggetti annidati l’uno dentro l’altro, dove alcuni non lo fanno. Sembra qualcosa come il seguente:

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

Questo mi dà problemi perché ho bisogno di scorrere l’array a volte, e l’incoerenza mi sta commettendo errori in questo modo:

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

Sono consapevole che posso dire if(ab){ console.log(abc)} , ma questo è straordinariamente noioso nei casi in cui ci sono fino a 5 o 6 oggetti annidati l’uno nell’altro. C’è un altro (più semplice) modo in cui posso farlo SOLO fare il console.log se esiste, ma senza lanciare un errore?

Quello che stai facendo solleva un’eccezione (e giustamente).

Puoi sempre farlo

 try{ window.abc }catch(e){ console.log("YO",e) } 

Ma non vorrei, invece, pensare al tuo caso d’uso.

Perché stai accedendo ai dati, sei livelli annidati di cui non hai familiarità? Quale caso d’uso lo giustifica?

Di solito, ti piacerebbe davvero convalidare quale tipo di object hai a che fare.

Inoltre, su una nota a margine non dovresti usare affermazioni come if(ab) perché restituirà false se ab è 0 o anche se è “0”. Invece, controlla se ab !== undefined

Una rapida soluzione consiste nell’utilizzare una funzione di aiuto try / catch con la funzione freccia ES6:

 function getSafe(fn, defaultVal) { try { return fn(); } catch (e) { return defaultVal; } } // use it like this getSafe(() => obj.a.lot.of.properties); // or add an optional default value getSafe(() => obj.a.lot.of.properties, 'nothing'); 

Vedi questo articolo per i dettagli.

Se sto capendo correttamente la tua domanda, vuoi il modo più sicuro per determinare se un object contiene una proprietà.

Il modo più semplice è usare la frase “in”.

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

Ovviamente puoi nidificare così profondamente come vuoi

 if ("a" in window.bc) { } 

Non sono sicuro se questo aiuta.

Se stai usando lodash , potresti usare la loro funzione “ha”. È simile al “in” nativo, ma consente i percorsi.

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

Questo è un problema comune quando si lavora con oggetti json profondi o complessi, quindi cerco di evitare il try / catch o l’incorporamento di più verifiche che renderebbero il codice illeggibile, di solito uso questo piccolo pezzo di codice in tutto il mio procect per fare il lavoro.

 /* ex: getProperty(myObj,'aze.xyz',0) // return myObj.aze.xyz safely * accepts array for property names: * getProperty(myObj,['aze','xyz'],{value: null}) */ function getProperty(obj, props, defaultValue) { var res, isvoid = function(x){return typeof x === "undefined" || x === null;} if(!isvoid(obj)){ if(isvoid(props)) props = []; if(typeof props === "string") props = props.trim().split("."); if(props.constructor === Array){ res = props.length>1 ? getProperty(obj[props.shift()],props,defaultValue) : obj[props[0]]; } } return typeof res === "undefined" ? defaultValue: res; } 

Uso religiosamente undefsafe . Mette alla prova ogni livello giù nel tuo object fino a quando non ottiene il valore che hai richiesto, o restituisce “indefinito”. Ma mai errori.

Prova questo. Se ab è undefiend, lascerà la frase if senza alcuna eccezione.

 if (ab && abc) { console.log(abc); } 

Nella risposta di str, verrà restituito il valore ‘undefined’ invece del valore predefinito impostato se la proprietà non è definita. Questo a volte può causare bug. Quanto segue si assicurerà che il defaultVal verrà sempre restituito quando la proprietà o l’object non sono definiti.

 const temp = {}; console.log(getSafe(()=>temp.prop, '0')); function getSafe(fn, defaultVal) { try { if (fn() === undefined) { return defaultVal } else { return fn(); } } catch (e) { return defaultVal; } } 

Ho risposto prima e ho fatto un controllo simile oggi. Una semplificazione per verificare se esiste una proprietà punteggiata nidificata. È ansible modificare questo per restituire il valore o alcuni valori predefiniti per raggiungere l’objective.

 function containsProperty(instance, propertyName) { // make an array of properties to walk through because propertyName can be nested // ex "test.test2.test.test" let walkArr = propertyName.indexOf('.') > 0 ? propertyName.split('.') : [propertyName]; // walk the tree - if any property does not exist then return false for (let treeDepth = 0, maxDepth = walkArr.length; treeDepth < maxDepth; treeDepth++) { // property does not exist if (!Object.prototype.hasOwnProperty.call(instance, walkArr[treeDepth])) { return false; } // does it exist - reassign the leaf instance = instance[walkArr[treeDepth]]; } // default return true; } 

Nella tua domanda potresti fare qualcosa del tipo:

 let test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}]; containsProperty(test[0], 'abc');