Как избежать ошибки "не удается прочитать свойство неопределенных"?
в моем коде я имею дело с массивом, который имеет некоторые записи со многими объектами, вложенными друг в друга, где, как и некоторые, нет. Это выглядит примерно так:
// where this array is hundreds of entries long, with a mix
// of the two examples given
var test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}];
Это дает мне проблемы, потому что мне нужно перебирать массив время от времени, и несоответствие бросает мне ошибки, как так:
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);
}
Я знаю, что могу сказать if(a.b){ console.log(a.b.c)}, но это чрезвычайно утомительно в тех случаях, когда есть до 5 или 6 объектов, вложенных в один другой. Есть ли другой (более простой) способ, которым я могу сделать это только на консоли.журнал, если он существует,но без ошибки?
9 ответов:
то, что вы делаете, вызывает исключение (и по праву).
вы всегда можете сделать
try{ window.a.b.c }catch(e){ console.log("YO",e) }но я бы не стал вместо этого думать о вашем случае использования.
почему вы получаете доступ к данным, 6 уровней вложенных, что вы не знакомы? Какой прецедент оправдывает это?
как правило, вы хотели бы на самом деле проверить, с каким объектом Вы имеете дело.
кроме того, на боковой ноте вы не должны использовать такие операторы, как
if(a.b)потому что возвращает false, если a.b равно 0 или даже если это "0". Вместо этого проверьте, еслиa.b !== undefined
быстрый обходной путь использует вспомогательную функцию try/catch с 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');посмотреть в этой статье для сведения.
Если я правильно понимаю ваш вопрос, вы хотите самый безопасный способ определить, если объект содержит свойство.
самый простой способ-использовать оператор "in".
window.a = "aString"; //window should have 'a' property //lets test if it exists if ("a" in window){ //true } if ("b" in window){ //false }конечно, вы можете вложить это так глубоко, как вы хотите
if ("a" in window.b.c) { }Не уверен, что это поможет.
Если вы используете лодашь, вы можете использовать их функцию "имеет". Он похож на родной "В", но допускает пути.
var testObject = {a: {b: {c: 'walrus'}}}; if(_.has(testObject, 'a.b.c')) { //Safely access your walrus here }
Это распространенная проблема при работе с глубоким или сложным объектом json, поэтому я стараюсь избегать try/catch или встраивания нескольких проверок, которые сделали бы код нечитаемым, я обычно использую этот маленький кусочек кода во всех моих проектах для выполнения этой работы.
/* 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; }
Я использую undefsafe Свято. Он проверяет каждый уровень вниз в ваш объект, пока он не получит значение, которое вы просили, или он возвращает "undefined". Но никогда не ошибается.
попробуйте это. Если
a.bявляется undefiend, он оставитifзаявление без каких-либо исключений.if (a.b && a.b.c) { console.log(a.b.c); }
в ответе str вместо заданного значения по умолчанию будет возвращено значение 'undefined', если свойство не определено. Это иногда может вызвать ошибки. Ниже будет убедиться, что defaultVal всегда будет возвращен, когда либо свойство или объект не определен.
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; } }
Я ответил на этот вопрос раньше и, как оказалось, делает аналогичную проверку сегодня. Упрощение, чтобы проверить, если существует вложенный пунктирной собственность. Вы можете изменить это, чтобы вернуть значение, или некоторые значения по умолчанию для достижения своей цели.
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; }в своем вопросе вы могли бы сделать что-то вроде:
let test = [{'a':{'b':{'c':"foo"}}}, {'a': "bar"}]; containsProperty(test[0], 'a.b.c');
Comments