Обновление атрибутов объекта JavaScript из другого объекта - программирование

Обновление атрибутов объекта JavaScript из другого объекта

Я хочу обновить объект, который может выглядеть следующим образом:

currentObject = {
    someValue : "value",
    myObject : {
        attribute1 : "foo",
        attribute2 : "bar"
    }
};

.. с объектом, который содержит некоторые изменения, а именно:

updateObject = {
    myObject : {
        attribute2 : "hello world"
    }
};

В конце я хотел бы обновить currentObject, чтобы:

currentObject.myObject.attribute2 == "hello world"

Это должно быть возможно и для других объектов. В качестве решения я подумал об итерации по объекту и как-то позабочусь о пространстве имен. Но я задаюсь вопросом, есть ли легкое решение этой проблемы, используя библиотеку, такую ​​как jQuery или прототип.

4b9b3361

Ответ 1

function update(obj/*, …*/) {
    for (var i=1; i<arguments.length; i++) {
        for (var prop in arguments[i]) {
            var val = arguments[i][prop];
            if (typeof val == "object") // this also applies to arrays or null!
                update(obj[prop], val);
            else
                obj[prop] = val;
        }
    }
    return obj;
}

должен сделать трюк: update(currentObject, updateObject). Возможно, вы захотите добавить некоторые проверки типов, например Object(obj) === obj, чтобы распространять только реальные объекты с реальными объектами, использовать правильный цикл для массивов или тегов hasOwnProperty.

Ответ 2

Я предлагаю использовать underscore.js(или лучше, lo-dash) extend:

_. extend (источник, * источники)

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

_.extend({name: 'moe'}, {age: 50});
=> {name: 'moe', age: 50}

Ответ 3

Простая реализация будет выглядеть так.

function copyInto(target /*, source1, sourcen */) {
    if (!target || typeof target !== "object")
        target = {};

    if (arguments.length < 2)
        return target;

    for (var len = arguments.length - 1; len > 0; len--)
        cloneObject(arguments[len-1], arguments[len]);

    return target;
}

function cloneObject(target, source) {
    if (!source || !target || typeof source !== "object" || typeof target !== "object")
        throw new TypeError("Invalid argument");

    for (var p in source)
        if (source.hasOwnProperty(p))
            if (source[p] && typeof source[p] === "object")
                if (target[p] && typeof target[p] === "object")
                    cloneObject(target[p], source[p]);
                else
                    target[p] = source[p];
            else 
                target[p] = source[p];
}

Это предполагает, что никакие наследуемые свойства не должны быть клонированы. Он также не проверяет такие объекты, как объекты DOM или примитивы в штучной упаковке.

Нам нужно выполнить итерацию в обратном порядке через аргументы, чтобы копия делалась в праве налево.

Затем мы создаем отдельную функцию cloneObject для обработки рекурсивного копирования вложенных объектов способом, который не мешает праву на левое копирование исходных аргументов объекта.

Он также гарантирует, что исходная цель является простым объектом.

Функция cloneObject выдаст ошибку, если ему был передан не объект.

Ответ 4

Здесь Object.keys и рекурсивный пример:

// execute object update function
update(currentObject, updateObject)

// instantiate object update function
function update (targetObject, obj) {
  Object.keys(obj).forEach(function (key) {

    // delete property if set to undefined or null
    if ( undefined === obj[key] || null === obj[key] ) {
      delete targetObject[key]
    }

    // property value is object, so recurse
    else if ( 
        'object' === typeof obj[key] 
        && !Array.isArray(obj[key]) 
    ) {

      // target property not object, overwrite with empty object
      if ( 
        !('object' === typeof targetObject[key] 
        && !Array.isArray(targetObject[key])) 
      ) {
        targetObject[key] = {}
      }

      // recurse
      update(targetObject[key], obj[key])
    }

    // set target property to update property
    else {
      targetObject[key] = obj[key]
    }
  })
}

JSFiddle demo.