如果我有对象的引用:

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

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


当前回答

我自动化了流程

if(isset(object,["prop1","prop2"])){
// YES!

}

function isset(object, props){
    var dump;
    try {
        for(var x in props){
            if(x == 0) {
                dump = object[props[x]];
                return;
            }
            dump = dump[props[x]];
        }
    } catch(e) {
        return false;
    }

    return true;
}

其他回答

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

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

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

另一种方式:

/**
 * This API will return particular object value from JSON Object hierarchy.
 *
 * @param jsonData : json type : JSON data from which we want to get particular object
 * @param objHierarchy : string type : Hierarchical representation of object we want to get,
 *                       For example, 'jsonData.Envelope.Body["return"].patient' OR 'jsonData.Envelope.return.patient'
 *                       Minimal Requirements : 'X.Y' required.
 * @returns evaluated value of objHierarchy from jsonData passed.
 */
function evalJSONData(jsonData, objHierarchy){
    
    if(!jsonData || !objHierarchy){
        return null;
    }
    
    if(objHierarchy.indexOf('["return"]') !== -1){
        objHierarchy = objHierarchy.replace('["return"]','.return');
    }
    
    let objArray = objHierarchy.split(".");
    if(objArray.length === 2){
        return jsonData[objArray[1]];
    }
    return evalJSONData(jsonData[objArray[1]], objHierarchy.substring(objHierarchy.indexOf(".")+1));
}

使现代化

看起来lodash已经为您的所有嵌套属性获取需求添加了_.get。

_.get(countries, 'greece.sparta.playwright')

https://lodash.com/docs#get


上一个答案

lodash用户可能喜欢lodash.contrib,它有几种方法可以缓解这个问题。

获取路径

签名:_.getPath(obj:Object,ks:String|Array)

基于所描述的路径获取嵌套对象中任何深度处的值给出的钥匙。键可以以数组或点分隔字符串的形式给出。如果无法到达路径,则返回undefined。

var countries = {
        greece: {
            athens: {
                playwright:  "Sophocles"
            }
        }
    }
};

_.getPath(countries, "greece.athens.playwright");
// => "Sophocles"

_.getPath(countries, "greece.sparta.playwright");
// => undefined

_.getPath(countries, ["greece", "athens", "playwright"]);
// => "Sophocles"

_.getPath(countries, ["greece", "sparta", "playwright"]);
// => undefined

我尝试了递归方法:

function objHasKeys(obj, keys) {
  var next = keys.shift();
  return obj[next] && (! keys.length || objHasKeys(obj[next], keys));
}

这个keys.length||退出递归,这样它就不会在没有键可供测试的情况下运行函数。测验:

obj = {
  path: {
    to: {
      the: {
        goodKey: "hello"
      }
    }
  }
}

console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey']));  // undefined

我正在使用它打印一组具有未知键/值的对象的友好html视图,例如:

var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
             ? myObj.MachineInfo.BiosInfo.Name
             : 'unknown';

另一个选项(接近这个答案):

function resolve(root, path){
    try {
        return (new Function(
            'root', 'return root.' + path + ';'
        ))(root);
    } catch (e) {}
}

var tree = { level1: [{ key: 'value' }] };
resolve(tree, 'level1[0].key'); // "value"
resolve(tree, 'level1[1].key'); // undefined

更多信息:https://stackoverflow.com/a/18381564/1636522