clone - object.assign deep copy - JavaScriptオブジェクトを正しくクローンするには?

JavaScript clone = Object / javascript / javascript-objects

オブジェクト x があります。私は、オブジェクトとしてそれをコピーしたいのですが y に変更するように、 y は変更しない x 。組み込みのJavaScriptオブジェクトから派生したオブジェクトをコピーすると、余分な不要なプロパティが発生することに気付きました。私は自分のリテラルで構築されたオブジェクトの1つをコピーしているので、これは問題ではありません。

Kamil Kiełczewski



Answer #1
function Circ() {
    this.me = this;
}

function Nested(y) {
    this.y = y;
}
var a = {
    x: 'a',
    circ: new Circ(),
    nested: new Nested('a')
};
var b = a;

b.x = 'b';
b.nested.y = 'b';

そうでなければ、この素晴らしい質問にたどり着くことさえできないからです。

console.log(a, b);

a --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}
var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';

では、その答えを見てみましょう。

function cloneSO(obj) {
    // 3つの単純なタイプ、およびnullまたは未定義を処理します
    if (null == obj || "object" != typeof obj) return obj;

    //日付を処理します
    if (obj instanceof Date) {
        var copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    //配列を処理します
    if (obj instanceof Array) {
        var copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = cloneSO(obj[i]);
        }
        return copy;
    }

    //オブジェクトを処理します
    if (obj instanceof Object) {
        var copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
        }
        return copy;
    }

    throw new Error("Unable to copy obj! Its type isn't supported.");
}
var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';
var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';
console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> Object {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}
function F() {};
function clonePF(o) {
    F.prototype = o;
    return new F();
}

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';
console.log(a, b);

a --> Object {
    x: "a",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

b --> F {
    x: "b",
    circ: Circ {
        me: Circ { ... }
    },
    nested: Nested {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true

調べてみると、これと同様の質問(Javascriptで、ディープコピーを実行するときに、プロパティが「this」であるためにサイクルを回避するにはどうすればよいですか?)が見つかりましたが、より良い解決策があります。

function cloneDR(o) {
    const gdcc = "__getDeepCircularCopy__";
    if (o !== Object(o)) {
        return o; //プリミティブ値
    }

    var set = gdcc in o,
        cache = o[gdcc],
        result;
    if (set && typeof cache == "function") {
        return cache();
    }
    // そうしないと
    o[gdcc] = function() { return result; }; //上書き
    if (o instanceof Array) {
        result = [];
        for (var i=0; i<o.length; i++) {
            result[i] = cloneDR(o[i]);
        }
    } else {
        result = {};
        for (var prop in o)
            if (prop != gdcc)
                result[prop] = cloneDR(o[prop]);
            else if (set)
                result[prop] = cloneDR(cache);
    }
    if (set) {
        o[gdcc] = cache; //リセット
    } else {
        delete o[gdcc]; //再度設定を解除します
    }
    return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';

そして、出力を見てみましょう...。

console.log(a, b);

a --> Object {
    x: "a",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "a"
    }
}

b --> Object {
    x: "b",
    circ: Object {
        me: Object { ... }
    },
    nested: Object {
        y: "b"
    }
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false

1つの葉を共有する木の構造はコピーされず、独立した2つの葉になります。

        [Object]                     [Object]
         /    \                       /    \
        /      \                     /      \
      |/_      _\|                 |/_      _\|  
  [Object]    [Object]   ===>  [Object]    [Object]
       \        /                 |           |
        \      /                  |           |
        _\|  |/_                 \|/         \|/
        [Object]               [Object]    [Object]