如果我有对象的引用:

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

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


当前回答

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

函数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'));//假的

其他回答

现在,我们还可以使用reduce循环嵌套键:

//@params o<对象>//@params路径<string>应为“obj.prop1.prop2.prop3”//返回:obj[path]值或“false”(如果prop不存在)const objPropIfExists=o=>路径=>{常量级别=路径.split('.');常量res=(levels.length>0)? level.reduce((a,c)=>a[c]||0,o):o[路径];return(!!res)?res:假}常量对象={name:'名称',sys:{country:“AU”},main:{temp:“34”,temp_min:“13”},能见度:“35%”}const exists=objPropIfExists(obj)('main.temp')const doesntExist=objPropIfExists(obj)('main.temp.foo.baz')console.log(存在,不存在)

我认为下面的脚本提供了更可读的表示。

声明函数:

var o = function(obj) { return obj || {};};

然后这样使用:

if (o(o(o(o(test).level1).level2).level3)
{

}

我称之为“悲伤小丑技巧”,因为它使用了符号o(


编辑:

这是TypeScript的版本

它在编译时提供类型检查(如果使用像Visual Studio这样的工具,还提供智能感知)

export function o<T>(someObject: T, defaultValue: T = {} as T) : T {
    if (typeof someObject === 'undefined' || someObject === null)
        return defaultValue;
    else
        return someObject;
}

用法相同:

o(o(o(o(test).level1).level2).level3

但这次intelligense奏效了!

此外,您可以设置默认值:

o(o(o(o(o(test).level1).level2).level3, "none")

我也遇到了同样的问题,我想看看是否能找到自己的解决方案。这接受要检查的路径作为字符串。

function checkPathForTruthy(obj, path) {
  if (/\[[a-zA-Z_]/.test(path)) {
    console.log("Cannot resolve variables in property accessors");
    return false;
  }

  path = path.replace(/\[/g, ".");
  path = path.replace(/]|'|"/g, "");
  path = path.split(".");

  var steps = 0;
  var lastRef = obj;
  var exists = path.every(key => {
    var currentItem = lastRef[path[steps]];
    if (currentItem) {
      lastRef = currentItem;
      steps++;
      return true;
    } else {
      return false;
    }
  });

  return exists;
}

下面是一些日志记录和测试用例的片段:

console.clear();var测试案例=[[“data.Messages[0].Code”,true],[“data.Messages[1].Code”,true],[“data.Messages[0]['Code']”,true],['data.Messages[0][“Code”]',true],[“data[Messages][0]['Code']”,错误],[“data['Messages'][0]['Code']”,真]];var path=“data.Messages[0].Code”;变量obj={数据:{消息:[{代码:“0”}, {代码:“1”}]}}函数checkPathForTruthy(obj,路径){if(/\[[a-zA-Z_]/.test(路径)){console.log(“无法解析属性访问器中的变量”);return false;}path=路径替换(/\[/g,“.”);path=路径替换(/]|'|“/g,”“);path=路径拆分(“.”);var步数=0;var lastRef=obj;var logOutput=[];var exists=path.every(key=>{var currentItem=lastRef[path[steps]];if(currentItem){logOutput.push(currentItem);lastRef=当前项;步骤++;返回true;}其他{return false;}});console.log(存在,logOutput);返回存在;}testCase.forEach(testCase=>{如果(checkPathForTruthy(obj,testCase[0])==testCase[1]){console.log(“通过:”+testCase[0]);}其他{console.log(“失败:”+testCase[0]+“预期”+testCase[1]);}});

下面是我的看法-这些解决方案中的大多数都忽略了嵌套数组的情况,如:

    obj = {
        "l1":"something",
        "l2":[{k:0},{k:1}],
        "l3":{
            "subL":"hello"
        }
    }

我可能想检查obj.l2[0].k

使用下面的函数,您可以执行深度测试('l2[0].k',obj)

如果对象存在,函数将返回true,否则返回false

函数deeptest(keyPath,testObj){变量obj;keyPath=keyPath.split('.')var cKey=keyPath.shift();函数get(pObj,pKey){var bracketStart,bracketEnd,o;bracketStart=pKey.indexOf(“[”);if(bracketStart>-1){//检查嵌套数组bracketEnd=pKey.indexOf(“]”);var arrIndex=pKey.substr(bracketStart+1,bracketEnd-bracketStart-1);pKey=pKey.substr(0,括号开始);var n=pObj[pKey];o=n?n[arrIndex]:未定义;}其他{o=pObj[pKey];}返回o;}obj=获取(testObj,cKey);while(obj&&keyPath.length){obj=get(obj,keyPath.shift());}返回typeof(obj)!=='未定义';}变量obj={“l1”:“级别1”,“arr1”:[{“k”:0},{“k”:1},{“k”:2}],“子”:{“a”:“字母a”,“b”:“字母b”}};console.log(“l1:”+深度测试(“l1”,obj));console.log(“arr1[0]:”+深度测试(“arr1[0]”,obj));console.log(“arr1[1].k:”+深度测试(“arr1].k”,obj));console.log(“arr1[1].j:”+深度测试(“arr1].j”,obj));console.log(“arr1[3]:”+深度测试(“arr1[3]”,obj));console.log(“arr2:”+深度测试(“arr2”,obj));

我知道这个问题很古老,但我想通过将其添加到所有对象来提供一个扩展。我知道人们倾向于不赞成使用Object原型来实现扩展的对象功能,但我发现没有什么比这更容易的了。此外,现在还允许使用Object.defineProperty方法。

Object.defineProperty( Object.prototype, "has", { value: function( needle ) {
    var obj = this;
    var needles = needle.split( "." );
    for( var i = 0; i<needles.length; i++ ) {
        if( !obj.hasOwnProperty(needles[i])) {
            return false;
        }
        obj = obj[needles[i]];
    }
    return true;
}});

现在,为了测试任何对象中的任何属性,只需执行以下操作:

if( obj.has("some.deep.nested.object.somewhere") )

这里有一个jsfiddle来测试它,特别是它包含一些jQuery,如果您直接修改Object.prototype,因为属性变为可枚举,则会中断。这对于第三方图书馆来说应该很好。