Поскольку на этот вопрос, как представляется, получены неправильные ответы, я ‘ Я просто укажу правильный ответ от

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

аналогичного вопроса obj.foo.bar.foobar. Я создал тестовый пример

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");

jsPerf.com. edit: я создал

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;
    }
}

Use:

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

тестовый набор jsPerf.com для сравнения принятого ответа с моей версией. Оказывается, что моя версия быстрее, особенно когда вы идти очень глубоко 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");

Все решения переопределяют любые исходные данные при настройке, поэтому я настроил следующее, превратив их в один объект:

Все решения переопределяют любые исходные данные при настройке, поэтому я настроил следующее, превратив их в один объект:

Можно также измените функции на метод Oject.prototype, изменив параметр obj следующим образом:

 var obj = {}
 nestObject.set(obj, "a.b", "foo"); 
 nestObject.get(obj, "a.b"); // 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;
     }
 };

Я знаю, что он старый, но я вижу только пользовательские функции в ответах.

Object.prototype = { setNested = function(){ ... }, getNested = function(){ ... } } 

{}.setNested('a.c','foo') 

Если вы не возражаете против использования библиотеки, посмотрите на
Вот простая функция, которая делает это, используя ссылку. Если второй аргумент не задан, он вернет пустой объект с первым аргументом, который будет использоваться в качестве прототипа возвращаемого объекта (первый объект, который будет использоваться в прототипе возвращаемого объекта цепь). _.set и _.get.

Вот тот, который возвращает обновленный объект

    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;
    }

Вот функция get и set, которую я только что скомпилировал из пары потоков некоторого пользовательского кода.

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'} }

Это также создаст ключи, которые не существуют на съемочной площадке.

Никаких рекурсий или обратных вызовов.

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;
}

Вы можете разделить путь и проверить, существует ли следующий элемент. Если нет, присвойте объект новому свойству.

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);

Возвратите тогда значение свойства.

В конце присвойте значение.

Я искал ответ, что

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);

не перезаписывает существующие значения и легко читается и смог придумать это. Оставьте это здесь, если это поможет другим с такими же потребностями То же, что и ответы Rbar, очень полезно, когда вы работаете с

function setValueAtObjectPath(obj, pathString, newValue) {
  // create an array (pathComponents) of the period-separated path components from pathString
  var pathComponents = pathString.split('.');
  // create a object (tmpObj) that references the memory of obj
  var tmpObj = obj;

  for (var i = 0; i < pathComponents.length; i  ) {
    // if not on the last path component, then set the tmpObj as the value at this pathComponent
    if (i !== pathComponents.length-1) {
      // set tmpObj[pathComponents[i]] equal to an object of it's own value
      tmpObj[pathComponents[i]] = {...tmpObj[pathComponents[i]]}
      // set tmpObj to reference tmpObj[pathComponents[i]]
      tmpObj = tmpObj[pathComponents[i]]
    // else (IS the last path component), then set the value at this pathComponent equal to newValue 
    } else {
      // set tmpObj[pathComponents[i]] equal to newValue
      tmpObj[pathComponents[i]] = newValue
    }
  }
  // return your object
  return obj
}

редукционными редукторами . Я использую клон lodash вместо оператора распространения для поддержки массивов: javascript — Объяснение `let` и блока scoop with для циклов — Stack Overflow

export function cloneAndPatch(obj, path, newValue, separator='.') {
    let stack = Array.isArray(path) ? path : path.split(separator);
    let newObj = _.clone(obj);

    obj = newObj;

    while (stack.length > 1) {
        let property = stack.shift();
        let sub = _.clone(obj[property]);

        obj[property] = sub;
        obj = sub;
    }

    obj[stack.shift()] = newValue;

    return newObj;
}