在(部分)未定义的对象中分配嵌套值

时间:2016-08-07 16:55:48

标签: javascript

我想要分配一个这样的值:

x.label1.label2.label3 = someValue;
// or equivalently:
x['label1']['label2']['label3'] = someValue;

只要定义了x.label1.label2,它就会起作用,否则会遇到引用错误。这当然有道理。但是,它是否有一种简单的方法来分配它,只需创建必要的嵌套对象?

例如,如果x等于{ label1: {}, otherLabel: 'otherValue' },我想将x更新为{ label1: { label2: { label3: someValue } }, otherLabel: otherValue }

我想我可能自己编写一个函数,但有没有语言功能或标准库函数可以做到这一点?

5 个答案:

答案 0 :(得分:1)

  

是否有语言功能或标准库功能来执行此操作

没有。您必须编写自己的函数或使用提供此类功能的库。

相关:How to set object property (of object property of..) given its string name in JavaScript?

答案 1 :(得分:1)

使用Proxy类可以部分实现。您可以将对象包装在Proxy中,并在访问不存在的属性时覆盖get陷阱以创建同一代理的另一个副本。这使您可以递归地创建“深度”属性。一个例子:

let traps = {
    get: function (target, name) {
        if (!(name in target))
            target[name] = new Proxy({}, traps);

        return target[name];
    }
};

let x = new Proxy({}, traps);

然后你会像任何对象一样使用x,除非它有这种特殊行为:

x.label1.label2.label3 = 'foo';

创建对象的嵌套层次结构。但请注意,即使您访问不存在的属性,也会创建一个对象。因此,您必须使用in关键字来检查它是否确实包含给定的属性。

答案 2 :(得分:1)

我认为你确实应该使用自定义功能,例如:

function assignByPath(obj, path, value) {
  var field = path.split('>'),
      last = field.pop();

  field.reduce(
    function(node, f) {
      return node[f] = node[f] instanceof Object ? node[f] : {};
    }, obj
  )[last] = value;
}

var myObj = {};
assignByPath(myObj, 'label1>label2>label3', 'someValue');

console.log(myObj);

理论上,您还可以覆盖Object.prototype,这样您就可以:

myObj.assignByPath('label1>label2>label3', 'someValue');

但我不建议这样做。

答案 3 :(得分:1)

您可以使用Array.prototype.shift()Object.assign(),递归

var x = {
  label1: {},
  otherLabel: "otherValue"
};

var nestprops = (props, value, obj, o, curr = props.shift()) => props.length 
  ? nestprops(props, value, (Object.assign(obj, {[curr]: {}}) && obj[curr]), o) 
  : ((!value || value) && (obj[curr] = value) && o);

console.log(nestprops(["label1", "label2", "label3"], "someValue", x, x));

答案 4 :(得分:0)

检查label1 object内的的长度是否等于0,然后将其修改为所需的对象

以下是代码段,希望有所帮助。

var obj = { label1: {}, otherLabel: 'otherValue' };

if(Object.keys(obj.label1).length == 0 ) {
    obj.label1 = { label2: { label3: "value3" } };
}
console.log(obj);