Обновление атрибутов объекта JavaScript из другого объекта
Я хочу обновить объект, который может выглядеть следующим образом:
currentObject = {
someValue : "value",
myObject : {
attribute1 : "foo",
attribute2 : "bar"
}
};
.. с объектом, который содержит некоторые изменения, а именно:
updateObject = {
myObject : {
attribute2 : "hello world"
}
};
В конце я хотел бы обновить currentObject, чтобы:
currentObject.myObject.attribute2 == "hello world"
Это должно быть возможно и для других объектов.
В качестве решения я подумал об итерации по объекту и как-то позабочусь о пространстве имен. Но я задаюсь вопросом, есть ли легкое решение этой проблемы, используя библиотеку, такую как jQuery или прототип.
Ответы
Ответ 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.