如果我有对象的引用:

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

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


当前回答

另一个ES5解决方案:

function hasProperties(object, properties) {
    return !properties.some(function(property){
        if (!object.hasOwnProperty(property)) {
            return true;
        }
        object = object[property];
        return false;
    });
}

其他回答

基于这个答案,我使用ES2015提出了一个通用函数,可以解决这个问题

function validChain( object, ...keys ) {
    return keys.reduce( ( a, b ) => ( a || { } )[ b ], object ) !== undefined;
}

var test = {
  first: {
    second: {
        third: "This is not the key your are looking for"
    }
  }
}

if ( validChain( test, "first", "second", "third" ) ) {
    console.log( test.first.second.third );
}

我尝试了递归方法:

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';

我在寻找属性存在时返回的值,所以我通过上面的CMS修改了答案。下面是我想到的:

函数getNestedProperty(obj,key){//从键字符串获取属性数组var财产=key.split(“.”);//遍历财产,如果对象为空或属性不存在,则返回未定义的对于(var i=0;i<属性.length;i++){if(!obj||!obj.hasOwnProperty(财产[i])){回来}obj=obj[财产[i]];}//找到嵌套属性,因此返回值返回obj;}用法:getNestedProperty(测试,“level.level2.level3”)//“level3”getNestedProperty(测试,“level.level2.foo”)//未定义

一个简单的方法是:

try {
    alert(test.level1.level2.level3);
} catch(e) {
    alert("undefined");    // this is optional to put any output here
}

try/catch捕捉未定义任何更高级别对象(如test、test.level1、test.level1.level2)时的情况。

另一种解决方法是,例如,使用以下对象:

var x = {
    a: {
        b: 3
    }
};

然后,我所做的是向这个对象添加以下函数:

x.getKey = function(k){
        var r ;
        try {
            r = eval('typeof this.'+k+' !== "undefined"');
        }catch(e){
            r = false;
        }
        if(r !== false){
            return eval('this.'+k);
        }else{
            console.error('Missing key: \''+k+'\'');
            return '';
        }
    };

然后您可以测试:

x.getKey('a.b');

如果未定义,则函数返回“”(空字符串),否则返回现有值。

还请考虑检查链接的另一个更复杂的解决方案:JS对象具有属性深度检查

Object.prototype.hasOwnNestedProperty = function(propertyPath){
    if(!propertyPath)
        return false;

    var properties = propertyPath.split('.');
    var obj = this;

    for (var i = 0; i < properties.length; i++) {
        var prop = properties[i];

        if(!obj || !obj.hasOwnProperty(prop)){
            return false;
        } else {
            obj = obj[prop];
        }
    }

    return true;
};

// Usage: 
var obj = {
   innerObject:{
       deepObject:{
           value:'Here am I'
       }
   }
}

obj.hasOwnNestedProperty('innerObject.deepObject.value');

注:还有一个递归版本。