如果我有对象的引用:

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 getValue(base, strValue) {

    if(base == null) return;
    
    let currentKey = base;
    
    const keys = strValue.split(".");
    
    let parts;
    
    for(let i=1; i < keys.length; i++) {
        parts = keys[i].split("[");
        if(parts == null || parts[0] == null) return;
        let idx;
        if(parts.length > 1) { // if array
            idx = parseInt(parts[1].split("]")[0]);
            currentKey = currentKey[parts[0]][idx];
        } else {
            currentKey = currentKey[parts[0]];
        }
        if(currentKey == null) return;
    }
    return currentKey;
}

如果结果在嵌套或值本身的任何地方失败,则调用函数返回undefined

const a = {
  b: {
    c: [
      {
        d: 25
      }
    ]
  }
}
console.log(getValue(a, 'a.b.c[1].d'))
// output
25

其他回答

如果像字符串一样处理名称:“t.level1。level2。level3”,则可以在任何深度读取对象属性。

window.t={level1:{level2:{level3: 'level3'}}};

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

alert(deeptest('t.level1.level2.level3') || 'Undefined');

如果任何段未定义,则返回undefined。

另一个版本:

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

nestedPropertyExists({a:{b:{c:1}}}, ['a','b','c']); // returns true
nestedPropertyExists({a:{b:{c:1}}}, ['a','b','c','d']); // returns false

这个问题由来已久。今天,您可以使用可选链接(?.)

let value = test?.level1?.level2?.level3;

资料来源:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

我以以下方式使用函数。

var a = {};
a.b = {};
a.b.c = {};
a.b.c.d = "abcdabcd";

function isDefined(objectChainString) {
    try {
        var properties = objectChainString.split('.');
        var currentLevel = properties[0];
        if (currentLevel in window) {
            var consolidatedLevel = window[currentLevel];
            for (var i in properties) {
                if (i == 0) {
                    continue;
                } else {
                    consolidatedLevel = consolidatedLevel[properties[i]];
                }
            }
            if (typeof consolidatedLevel != 'undefined') {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } catch (e) {
        return false;
    }
}

// defined
console.log(checkUndefined("a.b.x.d"));
//undefined
console.log(checkUndefined("a.b.c.x"));
console.log(checkUndefined("a.b.x.d"));
console.log(checkUndefined("x.b.c.d"));

我创建了一个小函数来安全地获取嵌套对象财产。

function getValue(object, path, fallback, fallbackOnFalsy) {
    if (!object || !path) {
        return fallback;
    }

    // Reduces object properties to the deepest property in the path argument.
    return path.split('.').reduce((object, property) => {
       if (object && typeof object !== 'string' && object.hasOwnProperty(property)) {
            // The property is found but it may be falsy.
            // If fallback is active for falsy values, the fallback is returned, otherwise the property value.
            return !object[property] && fallbackOnFalsy ? fallback : object[property];
        } else {
            // Returns the fallback if current chain link does not exist or it does not contain the property.
            return fallback;
        }
    }, object);
}

或者更简单但稍微不可读的版本:

function getValue(o, path, fb, fbFalsy) {
   if(!o || !path) return fb;
   return path.split('.').reduce((o, p) => o && typeof o !== 'string' && o.hasOwnProperty(p) ? !o[p] && fbFalsy ? fb : o[p] : fb, o);
}

或者更短,但没有错误标志:

function getValue(o, path, fb) {
   if(!o || !path) return fb;
   return path.split('.').reduce((o, p) => o && typeof o !== 'string' && o.hasOwnProperty(p) ? o[p] : fb, o);
}

我测试了:

const obj = {
    c: {
        a: 2,
        b: {
            c: [1, 2, 3, {a: 15, b: 10}, 15]
        },
        c: undefined,
        d: null
    },
    d: ''
}

下面是一些测试:

// null
console.log(getValue(obj, 'c.d', 'fallback'));

// array
console.log(getValue(obj, 'c.b.c', 'fallback'));

// array index 2
console.log(getValue(obj, 'c.b.c.2', 'fallback'));

// no index => fallback
console.log(getValue(obj, 'c.b.c.10', 'fallback'));

要查看所有包含文档和测试的代码,您可以查看我的github要点:https://gist.github.com/vsambor/3df9ad75ff3de489bbcb7b8c60beebf4#file-javascriptgetnestedvalues js