Como definir a propriedade do object (da propriedade do object de ..) dado seu nome de string em JavaScript?

Suponha que só nos seja dado

var obj = {}; var propName = "foo.bar.foobar"; 

Como podemos definir a propriedade obj.foo.bar.foobar para um determinado valor (digamos “hello world”)? Então eu quero conseguir isso, enquanto nós só temos o nome da propriedade em uma string:

 obj.foo.bar.foobar = "hello world"; 

     function assign(obj, prop, value) { if (typeof prop === "string") prop = prop.split("."); if (prop.length > 1) { var e = prop.shift(); assign(obj[e] = Object.prototype.toString.call(obj[e]) === "[object Object]" ? obj[e] : {}, prop, value); } else obj[prop[0]] = value; } var obj = {}, propName = "foo.bar.foobar"; assign(obj, propName, "Value"); 

    Como esta pergunta parece ser respondida por respostas incorretas, vou me referir à resposta correta de uma pergunta semelhante

     function setDeepValue(obj, value, path) { if (typeof path === "string") { var path = path.split('.'); } if(path.length > 1){ var p=path.shift(); if(obj[p]==null || typeof obj[p]!== 'object'){ obj[p] = {}; } setDeepValue(obj[p], value, path); }else{ obj[path[0]] = value; } } 

    Usar:

     var obj = {}; setDeepValue(obj, 'Hello World', 'foo.bar.foobar'); 

    edit: Eu criei um testcase jsPerf.com para comparar a resposta aceita com a minha versão. Acontece que minha versão é mais rápida, especialmente quando você vai muito fundo.

    http://jsfiddle.net/9YMm8/

     var nestedObjectAssignmentFor = function(obj, propString, value) { var propNames = propString.split('.'), propLength = propNames.length-1, tmpObj = obj; for (var i = 0; i < = propLength ; i++) { tmpObj = tmpObj[propNames[i]] = i !== propLength ? {} : value; } return obj; } var obj = nestedObjectAssignment({},"foo.bar.foobar","hello world"); 

    Detalhes

    Detalhes

    Todas as soluções superaram qualquer um dos dados originais ao configurar, então eu ajustei o seguinte, também o fiz em um único object:

      var obj = {} nestObject.set(obj, "ab", "foo"); nestObject.get(obj, "ab"); // returns foo var nestedObject = { set: function(obj, propString, value) { var propNames = propString.split('.'), propLength = propNames.length-1, tmpObj = obj; for (var i = 0; i < = propLength ; i++) { if (i === propLength){ if(tmpObj[propNames[i]]){ tmpObj[propNames[i]] = value; }else{ tmpObj[propNames[i]] = value; } }else{ if(tmpObj[propNames[i]]){ tmpObj = tmpObj[propNames[i]]; }else{ tmpObj = tmpObj[propNames[i]] = {}; } } } return obj; }, get: function(obj, propString){ var propNames = propString.split('.'), propLength = propNames.length-1, tmpObj = obj; for (var i = 0; i <= propLength ; i++) { if(tmpObj[propNames[i]]){ tmpObj = tmpObj[propNames[i]]; }else{ break; } } return tmpObj; } }; 

    Também pode alterar funções para ser um método Oject.prototype alterando obj param para isso:

     Object.prototype = { setNested = function(){ ... }, getNested = function(){ ... } } {}.setNested('a.c','foo') 

    Eu sei que é um antigo, mas só vejo funções personalizadas nas respostas.
    Se você não se importar em usar uma biblioteca, veja a function lodash _.set e _.get .

    Aqui está um que retorna o object atualizado

     function deepUpdate(value, path, tree, branch = tree) { const last = path.length === 1; branch[path[0]] = last ? value : branch[path[0]]; return last ? tree : deepUpdate(value, path.slice(1), tree, branch[path[0]]); } const path = 'cat.dog'; const updated = deepUpdate('a', path.split('.'), {cat: {dog: null}}) // => { cat: {dog: 'a'} } 

    Aqui está uma function simples para fazer isso usando referência.

      function setValueByPath (obj, path, value) { var ref = obj; path.split('.').forEach(function (key, index, arr) { ref = ref[key] = index === arr.length - 1 ? value : {}; }); return obj; } 

    Um muito simples.

    Nenhuma recursion ou sobrecarga de retorno de chamada.

     function setDeepVal(obj, path, val) { var props = path.split('.'); for (var i = 0, n = props.length - 1; i < n; ++i) { obj = obj[props[i]] = obj[props[i]] || {}; } obj[props[i]] = val; return obj; } // TEST var obj = { hello : 'world' }; setDeepVal(obj, 'foo.bar.baz', 1); setDeepVal(obj, 'foo.bar2.baz2', 2); console.log(obj); 

    Aqui está uma function get e set que acabei de compilar a partir de um par de threads + algum código personalizado.

    Ele também irá criar chaves que não existem no set.

     function setValue(object, path, value) { var a = path.split('.'); var o = object; for (var i = 0; i < a.length - 1; i++) { var n = a[i]; if (n in o) { o = o[n]; } else { o[n] = {}; o = o[n]; } } o[a[a.length - 1]] = value; } function getValue(object, path) { var o = object; path = path.replace(/\[(\w+)\]/g, '.$1'); path = path.replace(/^\./, ''); var a = path.split('.'); while (a.length) { var n = a.shift(); if (n in o) { o = o[n]; } else { return; } } return o; } 

    Você poderia dividir o caminho e marcar se o elemento a seguir existe. Se não atribuir um object à nova propriedade.

    Retorne então o valor da propriedade.

    No final, atribua o valor.

     function setValue(object, path, value) { var fullPath = path.split('.'), way = fullPath.slice(), last = way.pop(); way.reduce(function (r, a) { return r[a] = r[a] || {}; }, object)[last] = value; } var object = {}, propName = 'foo.bar.foobar', value = 'hello world'; setValue(object, propName, value); console.log(object);