2013-02-08 105 views
51

在我的代码中,我处理的是一个数组,其中包含许多嵌套在另一个中的对象的条目,其中有些不这样做。它看起来像下面这样:如何避免'无法读取未定义的属性'错误?

// 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个对象嵌套在一起,这是非常乏味的。有没有其他(更简单)的方式,我可以只做console.log(如果存在),但不会抛出错误?

+3

错误可能是一个正常的Javascript异常,所以请尝试'try..catch'语句。也就是说,包含非常多元素的数组看起来像是一个设计问题。 – millimoose 2013-02-08 22:17:57

+3

如果您的结构在各个项目中不一致,那么检查存在有什么问题?真的,我会使用if(“b”在a.b)中的&&“c”中)。这可能是“乏味”的,但这就是你得到的不一致......正常的逻辑。 – Ian 2013-02-08 22:21:49

+2

你为什么要访问不存在的属性,为什么你不知道对象是怎么样的? – Bergi 2013-02-08 22:22:06

回答

31

你在做什么引发了一个例外(并且正确如此)。

你总是可以做

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

但我不会,反而觉得你的使用情况。

你为什么要访问数据,你不熟悉的6层嵌套?什么用例证明了这一点?

通常,你想实际验证你正在处理的是什么类型的对象。

此外,在附注中,您不应使用类似if(a.b)的语句,因为如果a.b为0或即使它为“0”,它也会返回false。相反,检查a.b !== undefined

+1

关于您的第一次编辑:这是合理的;我正在处理JSON结构化数据库条目,这样对象将缩放多级字段(即entries.users.messages.date等,其中不是所有的情况都有数据输入) – Ari 2013-02-08 22:23:23

+0

“如果ab为0,它将返回true “ - 不。 'typeof ab ===“undefined”&& ab!= null' - 在第一部分之后不需要做第二部分,并且更合理地做'if(“b”in a)' – Ian 2013-02-08 22:23:32

+0

@ Ian yeah,I显然这意味着它是相反的,即使ab是“0”,它也会返回错误。尼斯赶上 – 2013-02-08 22:24:43

11

如果我正确理解你的问题,你想要最安全的方式来确定一个对象是否包含一个属性。

最简单的方法是使用“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) { } 

不知道这是否有助于巢以此为深。

+0

这对我很有用,谢谢 – 2013-04-09 20:42:06

+1

你无法安全地将它嵌入到你想要的深处。如果'window.b'是未定义的呢?你会得到一个类型错误:'不能在'运算符'中使用'undefined'搜索'c' – Trevor 2017-08-28 23:34:46

7

如果您使用lodash,则可以使用其“has”功能。它与本地“in”类似,但允许路径。

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

我虔诚地使用undefsafe。它会将每个级别测试到对象中,直到它获得您要求的值,否则返回“undefined”。但从来没有错误。

+2

与lodash类似'_.get' – Filype 2016-07-21 03:32:49

+0

好大声!如果你不需要lodash的其他功能仍然有用。 – martinedwards 2016-07-22 14:04:59

2

这是处理深层或复杂的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; 
} 
13

一种解决方法是使用一个try/catch辅助功能与ES6 arrow function

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

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

this article了解详情。

+2

这实在太神奇了! – Trevor 2017-08-28 23:34:00

1

试试这个。如果a.b是undefiend,则它将保留if语句,没有任何异常。

if (a.b && a.b.c) { 
    console.log(a.b.c); 
} 
相关问题