通过属性名数组访问嵌套对象

4

假设我有一个这样的对象(简化):

var options = {
    boxes: {
        size: {
            x: 15,
            y: 18
        },
    shadow: {
        [...]
    }
};

我有一个名字数组:

var names = ['boxes', 'size', 'x'];

在对象中根据数组获取/设置值的简单方法是什么,在这个例子中,应该是:

options.boxes.size.x = somevalue;

有什么想法吗?
2个回答

4

没有简单的内置方法可以完成这个任务。您需要编写自己的方法:

function getPath(obj, props) {
    for(var i = 0; i < props.length; i++) {
        if (props[i] in obj) {
            obj = obj[props[i]];
        } else {
            return; // not found
        }
    }

    return obj;
}

function setPath(obj, value, props) {
    for(var i = 0; i < props.length - 1; i++) {
        if (props[i] in obj) {
            obj = obj[props[i]];
        } else {
            return; // not found
        }
    }

    obj[props[i]] = value;
}

alert(getPath(options, names)); // 15
setPath(options, 25, names);  
alert(getPath(options, names)); // 25

4

只需要使用一个循环来迭代names并获取当前名称的下一个嵌套对象。假值或数组的末尾应停止循环。

var obj = options;
var i = 0;

while (obj && i < names.length)
    obj = obj[names[i++]];

或者直接使用.reduce()

names.reduce(function(obj, name) {
    return obj && obj[name];
}, options);

当然,如果您喜欢,您可以命名并重复使用该函数。
function toPropertyIn(obj, name) {
    return obj && obj[name];
}

names.reduce(toPropertyIn, options);

创建一个getter/setter方法:
function nestedProp(obj, names, value) {
    if (arguments.length > 1)
        var setProp = names.pop();

    var res = names.reduce(function(obj, name) {
        return obj && obj[name];
    }, options);

    if (res && setProp !== undefined)
        res[setProp] = value;
    else
        return res;
}


nestedProp(options, names, "foo"); // to set

var val = nestedProp(options, names); // to get

1
第二个选项看起来很有趣,我会去看看。谢谢! - Lars Ebert
@LarsEbert:我错过了“set”部分。更新了一个单一的函数来处理两个部分。 - cookie monster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接