如果我有对象的引用:

var test = {};

可能(但不是立即)具有嵌套对象,例如:

{level1: {level2: {level3: "level3"}}};

检查深度嵌套对象中是否存在属性的最佳方法是什么?

警报(测试级别1);生成未定义,但警告(test.level1.level2.level3);失败。

我目前正在做这样的事情:

if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
    alert(test.level1.level2.level3);
}

但我想知道是否有更好的方法。


当前回答

这是我使用的一个小助手函数,对我来说,它非常简单明了。希望这对一些人有帮助:)。

static issetFromIndices(param, indices, throwException = false) {
    var temp = param;

    try {
        if (!param) {
            throw "Parameter is null.";
        }

        if(!Array.isArray(indices)) {
            throw "Indices parameter must be an array.";
        }

        for (var i = 0; i < indices.length; i++) {
            var index = indices[i];
            if (typeof temp[index] === "undefined") {
                throw "'" + index + "' index is undefined.";
            }


            temp = temp[index];
        }
    } catch (e) {
        if (throwException) {
            throw new Error(e);
        } else {
            return false;
        }
    }

    return temp;
}

var person = {
    hobbies: {
        guitar: {
            type: "electric"
        }
    }
};

var indices = ["hobbies", "guitar", "type"];
var throwException = true;

try {
    var hobbyGuitarType = issetFromIndices(person, indices, throwException);
    console.log("Yay, found index: " + hobbyGuitarType);
} catch(e) {
    console.log(e);
}

其他回答

我没有看到任何人使用代理的例子

所以我想出了自己的办法。它的优点是你不必对字符串进行插值。实际上,您可以返回一个可链接的对象函数并用它做一些神奇的事情

函数解析(目标){var noop=()=>{}//我们使用了一个noop函数,因此我们也可以调用方法返回新代理(noop{获取(noop,key){//如果键为_result,则返回最终结果返回键==“_result”? 目标:resolve(//使用目标值或未定义的值进行解析目标==未定义?未定义:目标[key])},//如果我们想测试一个函数,那么由于使用noop,我们可以这么做//而不是在代理中使用target应用(noop,that,args){返回解析(typeof target==“function”?target.apply(that,args):未定义)},})}//接受答案中的一些修改示例var测试={level1:{level2:()=>({level3:'level3'})}}var test1={key1:{key2:['item0‘]}}//您需要在最后获得_result以获得最终结果console.log(解析(测试).level1.level2().level3._result)console.log(解析(测试).level1.level2().level3.level4.level5._result)console.log(解析(test1).key1.key2[0].result)console.log(resolve(test1)[0].key.result)//不存在

以上代码适用于同步内容。但是,如何测试像ajax调用这样的异步功能呢?你是怎么测试的?

fetch('https://httpbin.org/get')
.then(function(response) {
  return response.json()
})
.then(function(json) {
  console.log(json.headers['User-Agent'])
})

确保可以使用async/await来消除一些回调。但如果你能做得更神奇呢?看起来像这样的东西:

fetch('https://httpbin.org/get').json().headers['User-Agent']

你可能会想知道所有的承诺和链条在哪里。。。这可能会阻碍你所知道的一切。。。但使用相同的代理技术,您实际上可以测试深度嵌套的复杂路径是否存在,而无需编写单个函数

函数解析(目标){返回新代理(()=>{}{获取(noop,key){return key==“then”?target.then.bind(target):解析(承诺.解决(目标).然后(目标=>{if(typeof target[key]==“function”)返回target[key].bind(target)返回目标[键]}))},应用(noop,that,args){返回解析(target.then(result=>{返回result.apply(即,args)}))},})}//这感觉非常同步,但仍然是非阻塞的:)resolve(window)//这将链接一个noop函数,直到您调用then().fetch('https://httpbin.org/get').json().headers[“用户代理”].then(console.log,console.warn)//如果它不存在,则会收到警告//也可以对第一个测试对象使用此方法//也可以,但最后必须调用.then()//另一个例子解析(窗口).fetch('https://httpbin.org/get?items=4&items=2').json().args参数.个项目//很好,您可以在没有准备好的情况下映射数组项.map(n=>~n*4).then(console.log,console.warn)//如果它不存在,则会收到警告

这是我从奥利弗·斯蒂尔那里学到的一个模式:

var level3 = (((test || {}).level1 || {}).level2 || {}).level3;
alert( level3 );

事实上,整篇文章讨论了如何在javascript中实现这一点。他决定使用上面的语法(一旦你习惯了,它就不那么难读了)作为成语。

您可以使用“.”分隔对象和路径

函数checkPathExist(obj,路径){var pathArray=路径.split(“.”)for(pathArray的var i){if(反射get(obj,i)){obj=obj[i];}其他{return false;}}返回true;}var测试={level1:{level2:{level3:‘level3‘}}}};console.log('level.level.level3=>',checkPathExist(测试,'level.level 2.level3'));//真的console.log('level.level.foo=>',checkPathExist(测试,'level.level 2.foo'));//假的

创建全局函数并在整个项目中使用

试试这个

函数isExist(arg){尝试{返回参数();}捕获(e){return false;}}让obj={a:5,b:{c:5}};console.log(isExist(()=>obj.b.c))console.log(isExist(()=>obj.b.foo))console.log(isExist(()=>obj.test.foo))

if条件

if(isExist(()=>obj.test.foo)){
   ....
}

简单使用https://www.npmjs.com/package/js-aid用于检查嵌套对象的包。