如果我有对象的引用:

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 propsExists(arg) {
  try {
    const result = arg()
  
    if (typeof result !== 'undefined') {
      return true
    }

    return false
  } catch (e) {
    return false;
  }
}

此函数还将测试0,null。如果他们在场,它也将返回真实。

例子:

函数propsExists(arg){尝试{常量结果=arg()if(结果类型!==“undefined”){返回true}return false}捕获(e){return false;}}让obj={测试:{a: 空,b: 0,c: 未定义,d: 4中,e: “嘿”,f: ()=>{},g: 5.4中,h: 假,i: 真的,j: {},k: [],我:{a: 1中,}}};console.log('obj.test.a',propsExists(()=>obj.test/a))console.log('obj.test.b',propsExists(()=>obj.test.b))console.log('obj.test.c',propsExists(()=>obj.test.c))console.log('obj.test.d',propsExists(()=>obj.test-d))console.log('obj.test.e',propsExists(()=>obj.test.ex))console.log('obj.test.f',propsExists(()=>obj.test-f))console.log('obj.test.g',propsExists(()=>obj.test/g))console.log('obj.test.h',propsExists(()=>obj.test.h))console.log('obj.test.i',propsExists(()=>obj.test-i))console.log('obj.test.j',propsExists(()=>obj.test.j))console.log('obj.test.k',propsExists(()=>obj.test.k))console.log('obj.test.l',propsExists(()=>obj.test/l))

其他回答

function isIn(string, object){
    var arr = string.split(".");
    var notFound = true;
    var length = arr.length;
    for (var i = 0; i < length; i++){
        var key = arr[i];
        if (!object.hasOwnProperty(key)){
            notFound = false;
            break;
        }
        if ((i + length) <= length){
            object = object[key];
        }
    }
    return notFound;
}
var musicCollection = {
    hasslehoff: {
        greatestHits : true
    }
};
console.log(isIn("hasslehoff.greatestHits", musicCollection));
console.log(isIn("hasslehoff.worseHits", musicCollection));

这里是我的基于字符串的分隔符版本。

我已经使用这个函数来访问深度嵌套对象的财产,它对我来说很有效。。。

这是函数

/**
 * get property of object
 * @param obj object
 * @param path e.g user.name
 */
getProperty(obj, path, defaultValue = '-') {
  const value = path.split('.').reduce((o, p) => o && o[p], obj);

  return value ? value : defaultValue;
}

这是我访问深度嵌套对象属性的方式

{{ getProperty(object, 'passengerDetails.data.driverInfo.currentVehicle.vehicleType') }}

我已经对这个问题提出的一些建议进行了性能测试(感谢cdMinix添加了lodash),结果如下。

免责声明#1将字符串转换为引用是不必要的元编程,可能最好避免。首先不要忘记你的推荐人。阅读类似问题的答案。免责声明#2我们在这里谈论的是每毫秒数百万次的操作。在大多数用例中,这些都不太可能产生很大的差异。了解每种方法的局限性,选择最有意义的方法。对我来说,我会采取一些类似于出于方便而减少的措施。

物体包裹(Oliver Steele)–34%–最快

var r1 = (((test || {}).level1 || {}).level2 || {}).level3;
var r2 = (((test || {}).level1 || {}).level2 || {}).foo;

原始解决方案(有疑问的建议)–45%

var r1 = test.level1 && test.level1.level2 && test.level1.level2.level3;
var r2 = test.level1 && test.level1.level2 && test.level1.level2.foo;

checkNested–50%

function checkNested(obj) {
  for (var i = 1; i < arguments.length; i++) {
    if (!obj.hasOwnProperty(arguments[i])) {
      return false;
    }
    obj = obj[arguments[i]];
  }
  return true;
}

get_if_exist–52%

function get_if_exist(str) {
    try { return eval(str) }
    catch(e) { return undefined }
}

有效链–54%

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

objHasKeys–63%

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

nestedPropertyExists–69%

function nestedPropertyExists(obj, props) {
    var prop = props.shift();
    return prop === undefined ? true : obj.hasOwnProperty(prop) ? nestedPropertyExists(obj[prop], props) : false;
}

_.获得–72%

深度测试–86%

function deeptest(target, s){
    s= s.split('.')
    var obj= target[s.shift()];
    while(obj && s.length) obj= obj[s.shift()];
    return obj;
}

悲伤的小丑–100%–最慢

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

var r1 = o(o(o(o(test).level1).level2).level3);
var r2 = o(o(o(o(test).level1).level2).foo);

根据@Stephane LaFlèche的回答,我提出了另一个剧本版本。

JSFiddle演示

var obj = {"a":{"b":{"c":"Hello World"}},"resTest":"potato","success":"This path exists"};
checkForPathInObject = function(object,path,value) {
        var pathParts   = path.split("."),
            result      = false;
        // Check if required parameters are set; if not, return false
        if(!object || typeof object == 'undefined' || !path || typeof path != 'string')
            return false;
        /* Loop through object keys to find a way to the path or check for value
         * If the property does not exist, set result to false
         * If the property is an object, update @object
         * Otherwise, update result */
        for(var i=0;i<pathParts.length;i++){
            var currentPathPart = pathParts[i];
            if(!object.hasOwnProperty( currentPathPart )) {
                result = false;
            } else if (object[ currentPathPart ] && path == pathParts[i]) {
                result = pathParts[i];
                break;
            } else if(typeof object[ currentPathPart ] == 'object') {
                object = object[ currentPathPart ];
            } else {
                result = object[ currentPathPart ];
            }
        }
        /* */
        if(typeof value != 'undefined' && value == result)
            return true;
        return result;
};
// Uncomment the lines below to test the script
// alert( checkForPathInObject(obj,'a.b.c') ); // Results "Hello World"
// alert( checkForPathInObject(obj,'a.success') ); // Returns false
// alert( checkForPathInObject(obj,'resTest', 'potato') ); // Returns true

如果您恰好使用AngularJs,则可以使用$parse服务检查是否存在深度对象属性,如下所示:

if( $parse('model.data.items')(vm) ) {
    vm.model.data.items.push('whatever');
}

为了避免这样的陈述:

if(vm.model && vm.model.data && vm.model.data.items) {
    ....
}

不要忘记将$parse服务注入控制器

有关详细信息:https://glebbahmutov.com/blog/angularjs-parse-hacks/