动态深度选择JavaScript对象

use*_*428 7 javascript properties object

使用单一属性这很容易:


var jsonobj = {
    "test": "ok"
}
var propname = "test";
// Will alert "ok"
alert(jsonobj[propname]);
Run Code Online (Sandbox Code Playgroud)

但我想要做的是使用嵌套属性:


var jsonobj = {
    "test": {
        "test2": "ok"
    }
}
var propname = "test.test2";
// Alerts undefined
alert(jsonobj[propname]);
Run Code Online (Sandbox Code Playgroud)

有没有办法选择嵌套的"动态"属性?我知道我可以做jsonobj.test.test2,但问题是propname可以更改为深度为1,2或3级的属性.(例如test,test.test2,......)

Jam*_*mes 12

function resolve(cur, ns) {

    var undef;

    ns = ns.split('.');

    while (cur && ns[0])
        cur = cur[ns.shift()] || undef;

    return cur;

}
Run Code Online (Sandbox Code Playgroud)

例如

// 1:
resolve({
    foo: { bar: 123 }
}, 'foo.bar'); // => 123


// 2:
var complex = {
    a: {
        b: [
            document.createElement('div')
        ]
    }
};

resolve(complex, 'a.b.0.nodeName'); // => DIV
Run Code Online (Sandbox Code Playgroud)

使用它的好处是,如果你尝试访问不存在的东西它不会抛出错误 - 它会优雅地返回undefined.


编辑:

在评论中,安迪提到这不会引起人们可能期望的错误.我同意获取undefined有点通用,没有办法判断你的价值是否真的得到了解决.所以,要解决这个问题,请尝试以下方法:

var resolve = (function(){

    var UNRESOLVED = resolve.UNRESOLVED = {};
    return resolve;

    function resolve(cur, ns) {

        var undef;

        ns = ns.split('.');

        while (cur && ns[0])
            cur = cur[ns.shift()] || undef;

        if (cur === undef || ns[0]) {
            return UNRESOLVED;
        }

        return cur;

    }

}());
Run Code Online (Sandbox Code Playgroud)

它将返回一个可以像这样检查的UNRESOLVED对象:

var result = resolve(someObject, 'a.b.c');

if (result === resolve.UNRESOLVED) {...}
Run Code Online (Sandbox Code Playgroud)

它并不完美,但它是(IMO)确定未解析的命名空间而不必抛出错误的最佳方法.如果您想要错误,那么请继续:

someObject.a.b.c; //...
Run Code Online (Sandbox Code Playgroud)