Como evitar erros ‘não é possível ler propriedade de indefinido’?

No meu código, eu lido com um array que tem algumas inputs com muitos objects nesteds dentro de um outro, enquanto outros não. Parece algo como o seguinte:

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

Isso está me dando problemas porque eu preciso percorrer a matriz às vezes, e a inconsistência está me causando erros assim:

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

Estou ciente de que posso dizer if(ab){ console.log(abc)} , mas isso é extraordinariamente enfadonho nos casos em que há até 5 ou 6 objects nesteds uns dentro dos outros. Existe alguma outra maneira (mais fácil) que eu possa tê-lo SOMENTE fazer o console.log, se existir, mas sem gerar um erro?

O que você está fazendo levanta uma exceção (e com razão).

Você sempre pode fazer

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

Mas eu não pensaria em seu caso de uso.

Por que você está acessando dados, 6 níveis nesteds dos quais você não está familiarizado? Que caso de uso justifica isso?

Normalmente, você gostaria de validar o tipo de object com o qual está lidando.

Além disso, em uma nota lateral, você não deve usar instruções como if(ab) porque ele retornará false se ab for 0 ou mesmo se for “0”. Em vez disso, verifique se ab !== undefined

Uma solução rápida é usar uma function auxiliar try / catch com a function de seta 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'); 

Veja este artigo para detalhes.

Se eu estou entendendo sua pergunta corretamente, você quer a maneira mais segura de determinar se um object contém uma propriedade.

A maneira mais fácil é usar a instrução “in”.

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

Claro que você pode aninhar isso tão profundo quanto quiser

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

Não tenho certeza se isso ajuda.

Se você estiver usando lodash , você pode usar a function “has”. É semelhante ao nativo “in”, mas permite caminhos.

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

Esse é um problema comum quando se trabalha com um object json profundo ou complexo, então tento evitar tentar / incorporar várias verificações que tornariam o código ilegível, geralmente uso esse pequeno código em todo o meu processo para fazer o trabalho.

 /* 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; } 

Eu uso undefsafe religiosamente. Ele testa cada nível no seu object até obter o valor solicitado ou retornar “indefinido”. Mas nunca erros.

Tente isso. Se ab é undefiend, ele deixará a instrução if sem qualquer exceção.

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

Na resposta de str, o valor ‘indefinido’ será retornado em vez do valor padrão definido se a propriedade for indefinida. Isso às vezes pode causar erros. Os itens a seguir garantirão que o defaultVal sempre será retornado quando a propriedade ou o object for indefinido.

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

Eu respondi isso antes e estava fazendo uma verificação semelhante hoje. Uma simplificação para verificar se existe uma propriedade pontilhada aninhada. Você poderia modificar isso para retornar o valor ou algum padrão para atingir sua meta.

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

Na sua pergunta você poderia fazer algo como:

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