次のようなオブジェクトを更新したい:
currentObject = {
someValue : "value",
myObject : {
attribute1 : "foo",
attribute2 : "bar"
}
};
..いくつかの変更を含むオブジェクト、つまり:
updateObject = {
myObject : {
attribute2 : "hello world"
}
};
最後にcurrentObjectを更新して、次のようにします。
currentObject.myObject.attribute2 == "hello world"
それは他のオブジェクトでも同様に可能であるはずです。解決策として、オブジェクトの反復処理を検討し、なんとかして名前空間を処理しました。しかし、jQueryやプロトタイプなどのライブラリを使用することで、その問題を簡単に解決できるかどうか疑問に思います。
_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
テストに正しいループを使用します。
Underscore.js(またはそれ以上、lo-dash)の使用をお勧めします extend :
_.extend(destination、* sources)
ソースオブジェクトのすべてのプロパティを宛先オブジェクトにコピーし、宛先オブジェクトを返します。 順番になっているので、最後のソースは前の引数の同じ名前のプロパティをオーバーライドします。
_.extend({name: 'moe'}, {age: 50}); => {name: 'moe', age: 50}
単純な実装は次のようになります。
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
関数はエラーをスローします。
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]
}
})
}