인터넷에서 대부분의 솔루션에는 몇 가지 문제가 있습니다. 그래서 나는 후속 답변을하기로 결정했는데, 여기에는 왜 받아 들여진 대답을 받아들이지 않아야하는지 포함되어 있습니다.
시작 상황
모든 자식과 자식 등 으로 자바 스크립트 를 딥 카피 하고 싶습니다 Object
. 내가하지 종류의 일반 개발자의 때죠하지만, 내가 Object
있다 정상 properties
, circular structures
심지어 nested objects
.
먼저 circular structure
a를 만들어 봅시다 nested object
.
function Circ() {
this.me = this;
}
function Nested(y) {
this.y = y;
}
Object
이름이 지정된 모든 것을 하나로 모 읍시다 a
.
var a = {
x: 'a',
circ: new Circ(),
nested: new Nested('a')
};
다음으로 a
이름이 지정된 변수 에 복사 b
하고 변경하려고합니다.
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"
}
}
이제 해결책을 찾아 보자.
JSON
내가 시도한 첫 번째 시도는을 사용하는 것 JSON
입니다.
var b = JSON.parse( JSON.stringify( a ) );
b.x = 'b';
b.nested.y = 'b';
너무 많은 시간을 낭비하지 마십시오 TypeError: Converting circular structure to JSON
.
재귀 사본 (허용 된 "답변")
허용되는 답변을 살펴 보겠습니다.
function cloneSO(obj) {
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = cloneSO(obj[i]);
}
return copy;
}
// Handle Object
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.");
}
좋아 보인다? 그것은 객체의 재귀 복사본이며 다른 유형도 처리 Date
하지만 필수는 아닙니다.
var b = cloneSO(a);
b.x = 'b';
b.nested.y = 'b';
재귀와 circular structures
함께 잘 작동하지 않습니다 ...RangeError: Maximum call stack size exceeded
기본 솔루션
내 동료와 말다툼을 한 후, 상사는 우리에게 무슨 일이 있었는지 물었고, 그는 인터넷 검색 후 간단한 해결책 을 찾았습니다 . 이라고 Object.create
합니다.
var b = Object.create(a);
b.x = 'b';
b.nested.y = 'b';
이 솔루션은 얼마 전에 Javascript에 추가되었으며 심지어 처리합니다 circular structure
.
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"
}
}
... 그리고 내부의 중첩 구조에서는 작동하지 않았습니다.
기본 솔루션을위한 폴리 필
Object.create
IE 8과 같은 구형 브라우저 에는 polyfill이 있습니다. Mozilla에서 권장하는 것과 같으며 물론 완벽하지는 않으며 네이티브 솔루션 과 동일한 문제가 발생 합니다 .
function F() {};
function clonePF(o) {
F.prototype = o;
return new F();
}
var b = clonePF(a);
b.x = 'b';
b.nested.y = 'b';
나는 놨는데 F
우리가 무엇을 살펴 가질 수 있도록 범위를 벗어난 instanceof
우리에게 있습니다.
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
기본 솔루션 과 동일한 문제 이지만 출력이 약간 더 나쁩니다.
더 나은 (그러나 완벽하지는 않은) 솔루션
주위를 파고 때, 나는 (비슷한 질문을 찾을 때문에 "이"?되는 속성하여 자바 스크립트, 깊은 복사를 수행 할 때, 어떻게,주기를 피하는가를 이 일에)하지만, 더 나은 방법 솔루션.
function cloneDR(o) {
const gdcc = "__getDeepCircularCopy__";
if (o !== Object(o)) {
return o; // primitive value
}
var set = gdcc in o,
cache = o[gdcc],
result;
if (set && typeof cache == "function") {
return cache();
}
// else
o[gdcc] = function() { return result; }; // overwrite
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; // reset
} else {
delete o[gdcc]; // unset again
}
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
요구 사항은 일치하지만, 변경을 포함하여 몇 가지 작은 문제, 거기에 여전히 instance
의 nested
와 circ
에가 Object
.
나뭇잎을 공유하는 나무의 구조는 복사되지 않으며 두 개의 독립적 인 나뭇잎이됩니다.
[Object] [Object]
/ \ / \
/ \ / \
|/_ _\| |/_ _\|
[Object] [Object] ===> [Object] [Object]
\ / | |
\ / | |
_\| |/_ \|/ \|/
[Object] [Object] [Object]
결론
재귀와 캐시를 사용하는 마지막 솔루션은 최고는 아니지만 객체 의 실제 깊은 복사입니다. 그것은 간단 처리 properties
, circular structures
및 nested object
,하지만 것 중 인스턴스까지 엉망 복제있다.
jsfiddle