इंटरनेट पर अधिकांश समाधानों के साथ कई समस्याएं हैं। इसलिए मैंने एक अनुवर्ती बनाने का फैसला किया, जिसमें शामिल है, क्यों स्वीकार किए गए उत्तर को स्वीकार नहीं किया जाना चाहिए।
प्रारंभिक स्थिति
मैं अपने सभी बच्चों और उनके बच्चों के साथ एक जावास्क्रिप्ट कॉपी करना चाहता हूं Object
। लेकिन जब से मैं एक सामान्य डेवलपर की तरह नहीं हूं, मेरे Object
पास सामान्य है properties
, circular structures
और यहां तक कि nested objects
।
तो चलो एक circular structure
और एक 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';
यह समाधान कुछ समय पहले जावास्क्रिप्ट में जोड़ा गया था और यहां तक कि हैंडल भी 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 की तरह पुराने ब्राउज़र में पॉलीफ़िल है। यह मोज़िला द्वारा अनुशंसित कुछ ऐसा है, और निश्चित रूप से, यह सही नहीं है और मूल समाधान के समान समस्या का परिणाम है ।
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