如果我有对象的引用:

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

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


当前回答

您可以使用递归函数来实现这一点。即使您不知道所有嵌套的对象键名称,也可以使用此方法。

function FetchKeys(obj) {
    let objKeys = [];
    let keyValues = Object.entries(obj);
    for (let i in keyValues) {
        objKeys.push(keyValues[i][0]);
        if (typeof keyValues[i][1] == "object") {
            var keys = FetchKeys(keyValues[i][1])
            objKeys = objKeys.concat(keys);
        }
    }
    return objKeys;
}

let test = { level1: { level2: { level3: "level3" } } };
let keyToCheck = "level2";
let keys = FetchKeys(test); //Will return an array of Keys

if (keys.indexOf(keyToCheck) != -1) {
    //Key Exists logic;
}
else {
    //Key Not Found logic;
}

其他回答

CMS解决方案工作得很好,但使用/语法可能更方便。我建议如下

var checkNested = function(obj, structure) {

  var args = structure.split(".");

  for (var i = 0; i < args.length; i++) {
    if (!obj || !obj.hasOwnProperty(args[i])) {
      return false;
    }
    obj = obj[args[i]];
  }
  return true;
};

您可以简单地使用使用点的对象表示法,而不是提供多个参数

var test = {level1:{level2:{level3:'level3'}} };

checkNested(test, 'level1.level2.level3'); // true
checkNested(test, 'level1.level2.foo'); // false

我编写了自己的函数,该函数采用所需的路径,并具有一个好的和坏的回调函数。

function checkForPathInObject(object, path, callbackGood, callbackBad){
    var pathParts = path.split(".");
    var currentObjectPath = object;

    // Test every step to see if it exists in object
    for(var i=0; i<(pathParts.length); i++){
        var currentPathPart = pathParts[i];
        if(!currentObjectPath.hasOwnProperty(pathParts[i])){
            if(callbackBad){
                callbackBad();
            }
            return false;
        } else {
            currentObjectPath = currentObjectPath[pathParts[i]];
        }
    }

    // call full path in callback
    callbackGood();
}

用法:

var testObject = {
    level1:{
        level2:{
            level3:{
            }
        }
    }
};


checkForPathInObject(testObject, "level1.level2.level3", function(){alert("good!")}, function(){alert("bad!")}); // good

checkForPathInObject(testObject, "level1.level2.level3.levelNotThere", function(){alert("good!")}, function(){alert("bad!")}); //bad

从这个答案开始,阐述了以下选项。两者的树相同:

var o = { a: { b: { c: 1 } } };

未定义时停止搜索

var u = undefined;
o.a ? o.a.b ? o.a.b.c : u : u // 1
o.x ? o.x.y ? o.x.y.z : u : u // undefined
(o = o.a) ? (o = o.b) ? o.c : u : u // 1

逐一确保每个级别

var $ = function (empty) {
    return function (node) {
        return node || empty;
    };
}({});

$($(o.a).b).c // 1
$($(o.x).y).z // undefined

我想我应该再加一个我今天想到的。我对这个解决方案感到自豪的原因是它避免了许多解决方案中使用的嵌套括号,例如Object Wrap(Oliver Steele):

(在本例中,我使用下划线作为占位符变量,但任何变量名称都有效)

//“测试”对象var测试={level1:{level2:{level3:‘level3‘}}}};设_=测试;如果((_=_level1)&&(_=.level2)&&{设level3=_;//做3级的事情}

//您也可以使用“stacked”if语句。如果你的物体很深,这会有帮助。//(除最后一个大括号外,不带嵌套或大括号)设_=测试;如果(_=_.level1)如果(_=_.level2)如果(_=_.level3){设level3=_;//做3级的事情}//或者可以缩进:如果(_=_.level1)如果(_=_.level2)如果(_=_.level3){设level3=_;//做3级的事情}

一个简短的ES5版本@CMS的优秀答案:

// Check the obj has the keys in the order mentioned. Used for checking JSON results.  
var checkObjHasKeys = function(obj, keys) {
  var success = true;
  keys.forEach( function(key) {
    if ( ! obj.hasOwnProperty(key)) {
      success = false;
    }
    obj = obj[key];
  })
  return success;
}

通过类似测试:

var test = { level1:{level2:{level3:'result'}}};
utils.checkObjHasKeys(test, ['level1', 'level2', 'level3']); // true
utils.checkObjHasKeys(test, ['level1', 'level2', 'foo']); // false