web-dev-qa-db-ja.com

別のオブジェクトからのJavaScriptオブジェクト属性の更新

次のようなオブジェクトを更新したい:

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

..いくつかの変更を含むオブジェクト、つまり:

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

最後にcurrentObjectを更新して、次のようにします。

currentObject.myObject.attribute2 == "hello world"

それは他のオブジェクトでも同様に可能であるはずです。解決策として、オブジェクトの反復処理を検討し、なんとかして名前空間を処理しました。しかし、jQueryやプロトタイプなどのライブラリを使用することで、その問題を簡単に解決できるかどうか疑問に思います。

32
Luca Hofmann
_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テストに正しいループを使用します。

11
Bergi

Underscore.js(またはそれ以上、lo-dash)の使用をお勧めします extend

_.extend(destination、* sources)

ソースオブジェクトのすべてのプロパティを宛先オブジェクトにコピーし、宛先オブジェクトを返します。 順番になっているので、最後のソースは前の引数の同じ名前のプロパティをオーバーライドします

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

単純な実装は次のようになります。

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関数はエラーをスローします。

1
user1689386

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デモ

0
bloodyKnuckles