JS用键名与“。”串联的字符串更新嵌套对象键。

时间:2018-10-21 05:46:02

标签: javascript object

让我们说我有这个对象:

var obj = {
  level1 :{
    level2: {
      level3: {
        title: "winner"
      }
    }
  }
}

现在,我想使用下一个字符串更新title键(注意,我有一个字符串,而不是实际变量) 我有: let myString = "level1.level2.level3.title"; // note - myString value comes from $http method or something

也许是这样的:

obj[myString] = "super-winner";

不幸的是,以上操作无效。

此外-有时我需要更新一个未定义的对象,因此我需要一些东西来使要使用新的空对象定义的对象。

例如,如果我有下一个对象:

var obj = {
  level1 : {}
  }
}

我仍然想用上述的level3.winner来修改obj

提醒: obj[myString] = "super-winner";

我该怎么做?

4 个答案:

答案 0 :(得分:1)

这有效

const obj = {
   // level1: {
    //     level2: {
    //         level3: {
    //             title: "winner"
    //         }
    //     }
    // }
}

const myString = "level1.level2.level3.title"; // note - myString value comes from $http method or something

const title = 'super-winner'

myString.split('.')
    .reduce(
        (acc, curr) => {
            if (acc[curr] === undefined && curr !== 'title') {
                acc[curr] = {}
            }

            if (curr === 'title') {
                acc[curr] = title
            }

            return acc[curr]
        }, obj
    );

console.log(obj) // {"level1":{"level2":{"level3":{"title":"super-winner"}}}}

这是一种零依赖解决方案,即您不必使用lodash或使应用程序规模变大的东西。

答案 1 :(得分:1)

使用“ reduce”来获得所需的结果。创建了一个函数“ updateValue”,您可以在其中传递obj-要修改的对象,str-要更改的属性路径,value-要在属性路径处分配的值

var obj1 = {
  level1 :{
    level2: {
      level3: {
        title: "winner"
      }
    }
  }
}

var obj2 = { level1: {} }

var obj3 = {
  level1 :{
    level2: {
      level3: {
        title: "winner"
      }
    }
  }
}

function updateValue(obj, str, value) {
let props = str.split('.'), arrIndex = -1
props.reduce((o,d,i) => ( 
                         arrIndex = d.indexOf('[') > -1 && d[d.indexOf('[') + 1],
                          arrIndex && (d = d.slice(0, d.indexOf('['))),
                           i == props.length - 1 
                              ? o[d] = value 
                              : (o[d] = o[d] || {}, (arrIndex && (Array.isArray(o[d]) || (o[d] = [o[d]]))), arrIndex && o[d][arrIndex] || o[d])
                        )
                , obj)
}

updateValue(obj1, 'level1.level2.level3.title', 'abcd')
updateValue(obj2, 'level1.level2.level3.title', 'abcd')
updateValue(obj3, 'level1.level2[0].title', 'abcd')

console.log(obj1)
console.log(obj2)
console.log(obj3)

答案 2 :(得分:0)

您可以使用.set https://lodash.com/docs#set

lodash功能

例如:_.set(obj, 'level1.level2.level3.title', 'super-winner');

或使用ES6语法功能:

var str = 'level1.level2.level3.title';
str.split('.').reduce((p, c, index) => {
    if (index === str.split('.').length - 1) {
        if (typeof p[c] !== "object") { // string, number, boolean, null, undefined
            p[c] = 'super-winner'
        }
        return p[c];
    } else {
        if (!p[c] || typeof p[c] !== 'object') {
            p[c] = {};
        }
        return p[c];
    }
}, obj)

console.log(obj);

答案 3 :(得分:0)

这可以手动完成,反复索引到对象结构中,并根据需要在到达目标键的路径上创建新对象:

const updateField = (o, path, entry) => {
  path = path.split(".");
  let curr = o;
  
  while (path.length > 1) {
    const dir = path.shift();    
    const parent = curr;
    curr = curr[dir];

    if (undefined === curr) {
      parent[dir] = {};
      curr = parent[dir];
    }
  }
  
  if (path.length === 1) {
    curr[path.shift()] = entry;
  }
  
  return o;
};

var obj = {
  level1 : {
    level2: {
      level3: {
        title: "winner"
      }
    }
  }
};

console.log(JSON.stringify(updateField(obj, "level1.level2.level3.title", "super-winner"), null, 2));
console.log(JSON.stringify(updateField({}, "level1.level2.level3.title", "super-winner"), null, 2));