在“if”条件下检查嵌套对象的更好方法

Better way for checking nested object in `if` condition?

本文关键字:对象 更好 方法 嵌套 检查 if 条件下      更新时间:2023-09-26

考虑我有一个这样的对象:

Obj.Boo.Foo.Zoo

好的,如果我想确定zoo有一个值并且不是空的,我应该这样做:

if(Obj != null && Obj.Boo != null && Obj.Boo.Foo != null && Obj.Boo.Foo.Zoo != null) {
    //blah blah
}

如果在Zoo之后有更多嵌套对象,我应该扩展if,代码就会变得有点格式错误。

有没有更好的方法来解决这种情况?

我保留了一个调用chainGet(obj, chain, default)的小函数,用于以下情况:

function chainGet(obj, chain, dflt) {
    if (typeof chain === "string")
        chain = chain.split(".");
    var result = obj;
    for (var i = 0; i < chain.length; i += 1) {
        if (result === undefined)
            break;
        result = result[chain[i]];
    }
    return result === undefined? dflt : result;
}

例如:

> chainGet({ foo: 42 }, "foo")
42
> chainGet({ foo: 42 }, "bar", "x")
'x'
> chainGet({ foo: { bar: 42 }}), "foo.bar")
42

这甚至适用于阵列:

> chainGet([{ foo: [42] }], [0, "foo", 0])
42

当然,长链的点式访问是一种代码气味,所以在使用它们时应该谨慎……但有时你只需要这样做;)

如果你真的不需要处理这样的情况,一个糟糕的做法是尝试在try-catch语句中访问对象

try{
    // access Obj.Boo.Foo.Zoo
}
catch{
    // catch a NullReferenceException
}

更好的方法是修改getter和setter,以便父对象在尝试访问子对象及其null时抛出合适的异常或处理此异常。在这种情况下,检查第一个对象就足够了。

它可以在不使用函数的情况下实现。快捷方式可以是-

if(((((Obj || {}).Boo || {}).Foo || {}).Zoo || {}) != {}) {
    // Zoo has a value and not empty
}

或者ES6方式-

const checkNull = (keys, Object) =>
  keys.reduce((Obj, o) =>
    (Obj && Obj[o]) ? Obj[o] : null, Object)
console.log(checkNull(['Boo', 'Foo', Zoo], Obj))
// [Value of Zoo]
console.log(checkNull(['Boo', 'Foo1', Zoo], Obj))
// null