जावास्क्रिप्ट में डीप क्लोन कैसे करें


105

आप एक जावास्क्रिप्ट ऑब्जेक्ट को कैसे क्लोन करते हैं?

मैं जानता हूँ कि जैसे चौखटे के आधार पर विभिन्न कार्यों के देखते हैं JSON.parse(JSON.stringify(o))और $.extend(true, {}, o)लेकिन मैं उस तरह एक ढांचे का उपयोग नहीं करना चाहते हैं।

एक गहरी क्लोन बनाने के लिए सबसे सुरुचिपूर्ण या कुशल तरीका क्या है।

हम क्लोन मामलों की तरह किनारे के मामलों के बारे में परवाह करते हैं। प्रोटोटाइप चेन नहीं तोड़ना, सेल्फ रेफरेंस से निपटना।

हम डोम ऑब्जेक्ट्स की नकल का समर्थन करने के बारे में परवाह नहीं करते हैं और इस कारण से .cloneNodeमौजूद हैं।

जैसा कि मैं मुख्य रूप node.jsसे वी 8 इंजन की ईएस 5 सुविधाओं का उपयोग करने में गहरी क्लोन का उपयोग करना चाहता हूं , स्वीकार्य है।

[संपादित करें]

इससे पहले कि कोई सुझाव दे कि मैं उल्लेख कर दूं कि ऑब्जेक्ट से प्रोटोटाइप के द्वारा प्रतिलिपि बनाने और इसे क्लोन करने के बीच एक अलग अंतर है। पूर्व प्रोटोटाइप श्रृंखला में गड़बड़ी करता है।

[आगे संपादित करें]

आपके उत्तर को पढ़ने के बाद मुझे गुस्सा आया कि पूरी वस्तुओं का क्लोन बनाना एक बहुत ही खतरनाक और कठिन खेल है। उदाहरण के लिए निम्न क्लोजर आधारित वस्तु को लें

var o = (function() {
     var magic = 42;

     var magicContainer = function() {
          this.get = function() { return magic; };
          this.set = function(i) { magic = i; };
     }

      return new magicContainer;
}());

var n = clone(o); // how to implement clone to support closures

क्या क्लोन फ़ंक्शन लिखने का कोई तरीका है जो ऑब्जेक्ट को क्लोन करता है, क्लोनिंग के समय एक ही स्थिति होती है, लेकिन oJS में JS पार्सर लिखे बिना स्थिति को बदल नहीं सकता है ।

अब ऐसे कार्य के लिए वास्तविक दुनिया की जरूरत नहीं होनी चाहिए। यह महज अकादमिक हित है।


2
इससे पहले कि यह डुप्लिकेट चिह्नित हो जाए, मैंने stackoverflow.com/questions/122102/… को देखा और ऐसा कोई जवाब नहीं मिला जो सभी एज मामलों से निपटा हो।
Raynos

"आगे संपादित करें" अनुभाग में आवश्यकता वस्तु से "सहायता" के बिना प्राप्त करना असंभव है, क्योंकि इस तरह के निजी चर वास्तव में निजी हैं , और परिणाम से एक सामान्य cloneफ़ंक्शन द्वारा सुलभ नहीं है । प्रश्न में वस्तु को अपनी स्वयं की दर्जी cloneपद्धति को उजागर करना चाहिए ।
त्रिनकोट

मैं आज रात एक गुच्छा के बारे में पढ़ रहा हूं, और मुझे जो संसाधन मिले उनमें यह बदसूरत दिखने वाला ब्लॉग पोस्ट था जिसमें ब्राउज़र में संरचित क्लोन एल्गोरिथम तक पहुंचने के लिए कुछ हैक शामिल हैं: dassur.ma/things/deep-copy
बिल्ली

जवाबों:


67

यह वास्तव में निर्भर करता है कि आप क्लोन क्या करना चाहते हैं। क्या यह वास्तव में JSON वस्तु है या जावास्क्रिप्ट में कोई वस्तु है? यदि आप कोई क्लोन करना चाहते हैं, तो यह आपको कुछ परेशानी में डाल सकता है। कौन सी परेशानी? मैं इसे नीचे बताऊंगा, लेकिन सबसे पहले, एक कोड उदाहरण जो क्लोन करता है, जो वास्तव में ऑब्जेक्ट, किसी भी आदिम, सरणियों और DOM नोड्स है।

function clone(item) {
    if (!item) { return item; } // null, undefined values check

    var types = [ Number, String, Boolean ], 
        result;

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item );
        }
    });

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = [];
            item.forEach(function(child, index, array) { 
                result[index] = clone( child );
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true );    
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item);
                } else {
                    // it is an object literal
                    result = {};
                    for (var i in item) {
                        result[i] = clone( item[i] );
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item;
                }
            }
        } else {
            result = item;
        }
    }

    return result;
}

var copy = clone({
    one : {
        'one-one' : new String("hello"),
        'one-two' : [
            "one", "two", true, "four"
        ]
    },
    two : document.createElement("div"),
    three : [
        {
            name : "three-one",
            number : new Number("100"),
            obj : new function() {
                this.name = "Object test";
            }   
        }
    ]
})

और अब, हम उन समस्याओं के बारे में बात करते हैं जो आपको वास्तविक वस्तुओं की क्लोनिंग करते समय मिल सकती हैं। मैं अब बात कर रहा हूँ, उन वस्तुओं के बारे में जो आप कुछ ऐसा करके बनाते हैं

var User = function(){}
var newuser = new User();

बेशक आप उन्हें क्लोन कर सकते हैं, यह कोई समस्या नहीं है, प्रत्येक ऑब्जेक्ट कंस्ट्रक्टर संपत्ति को उजागर करता है, और आप इसका उपयोग ऑब्जेक्ट क्लोन करने के लिए कर सकते हैं, लेकिन यह हमेशा काम नहीं करेगा। आप for inइस ऑब्जेक्ट पर सरल भी कर सकते हैं , लेकिन यह उसी दिशा में जाता है - परेशानी। मैंने कोड के अंदर क्लोन कार्यक्षमता को भी शामिल किया है, लेकिन इसे if( false )बयान से बाहर रखा गया है।

तो, क्लोनिंग एक दर्द क्यों हो सकता है? खैर, सबसे पहले, प्रत्येक वस्तु / उदाहरण में कुछ अवस्था हो सकती है। आप कभी भी यह सुनिश्चित नहीं कर सकते हैं कि आपकी वस्तुओं में उदाहरण के लिए एक निजी चर नहीं है, और यदि ऐसा है, तो ऑब्जेक्ट को क्लोन करके, आप बस राज्य को तोड़ देते हैं।

कल्पना कीजिए कि कोई राज्य नहीं है, यह ठीक है। फिर भी हमें एक और समस्या है। "कंस्ट्रक्टर" विधि के माध्यम से क्लोनिंग हमें एक और बाधा देगा। यह एक तर्क पर निर्भरता है। आप कभी भी निश्चित नहीं हो सकते हैं कि किसी ने इस वस्तु को बनाया है, नहीं किया है, किसी तरह का

new User({
   bike : someBikeInstance
});

यदि यह मामला है, तो आप भाग्य से बाहर हैं, someBikeInstance शायद किसी संदर्भ में बनाया गया था और यह संदर्भ क्लोन विधि के लिए अनकॉन्स्ड है।

इसलिए क्या करना है? आप अभी भी for inसमाधान कर सकते हैं, और ऐसी वस्तुओं का इलाज कर सकते हैं जैसे सामान्य वस्तु शाब्दिक, लेकिन शायद यह एक विचार है कि ऐसी वस्तुओं का क्लोन बिल्कुल भी नहीं है, और बस इस वस्तु के संदर्भ को पारित करें?

एक अन्य समाधान है - आप एक कन्वेंशन सेट कर सकते हैं कि जिन सभी वस्तुओं को क्लोन किया जाना चाहिए वे इस भाग को स्वयं लागू करें और उपयुक्त एपीआई विधि (जैसे क्लोनऑब्जेक्ट) प्रदान करें। cloneNodeडोम के लिए कुछ कर रहा है।

आप तय करें।


मैं उन वस्तुओं से निपटने में बाधा उत्पन्न करता था जो खुद को छिपाने के लिए क्लोजर का उपयोग करते हैं। कोई एक वस्तु और उसके पूरे राज्य को कैसे क्लोन कर सकता है लेकिन फिर भी यह सुनिश्चित कर सकता है कि क्लोन कठबोली मूल स्थिति को अपने आप बदल सकती है। result = new item.constructor();खराब होने का एक कुँवर बिंदु यह है कि आपको कंस्ट्रक्टर फ़ंक्शन और आइटम ऑब्जेक्ट दिए गए हैं, जो आपको कंस्ट्रक्टर में पारित किए गए किसी भी पैरामास्टर को आरई करने में सक्षम होना चाहिए।
रेयनोस

7
@ रेयानोस: यदि ऑब्जेक्ट राज्य को छिपाने के लिए क्लोजर का उपयोग करते हैं, तो आप उन्हें क्लोन नहीं कर सकते। इसलिए 'क्लोजर' शब्द। जैसा कि nemisj अंत में कहता है, सबसे अच्छा तरीका है कि अगर यह एक विकल्प है, तो क्लोनिंग (या क्रमांकन / deserialization) के लिए एपीआई विधि को लागू करना है।
२iel बजे मिचेल कालकमैन

@ मचिअलकल्मन मुझे एक एहसास था कि मामला क्या था। हालाँकि किसी के पास इसका वास्तव में एक चतुर समाधान हो सकता था।
रेयानोस

का प्रभाव क्या है false && item.constructor? क्या यह ifबेकार नहीं है ?
गेब्रियल पेट्रोव

2
@GabrielPetrovay यह ifकार्यात्मक दृष्टिकोण से 'बेकार' है, क्योंकि यह कभी नहीं चलेगा, लेकिन यह एक काल्पनिक कार्यान्वयन दिखाने का अकादमिक उद्देश्य है जिसे कोई भी उपयोग करने की कोशिश कर सकता है, जो लेखक ने बाद में समझाया गया कारण की सलाह नहीं देता है। तो, हाँ, यह elseस्थिति का मूल्यांकन किया गया है, और फिर भी कोड के वहाँ होने का एक कारण क्लॉज होगा।
गुई इमामुरा

155

बहुत सरल तरीका, शायद बहुत सरल:

var cloned = JSON.parse(JSON.stringify(objectToClone));

12
जब तक कोई ऑब्जेक्ट वैल्यू एक फ़ंक्शन नहीं है, तब तक आपको स्वीकृत उत्तर जैसी किसी चीज़ का उपयोग करना होगा। या cloneDeepलॉडश की तरह एक सहायक फ़ंक्शन का उपयोग करें ।
Matthoiland

31
यदि कोई ऑब्जेक्ट एक फ़ंक्शन है, तो ऑब्जेक्ट कोई JSON नहीं है।
जोस डे जोंग

5
क्या उपयोग मामला सिर्फ एक का उपयोग करने के बजाय एक समारोह क्लोन करने के लिए उचित हो सकता है?
जी। ग़ज़

3
अगर मुझे सही से याद है तो यह तारीखों को तार में बदल देता है।
पीटर

3
@ G.Ghez यदि आप एक ऐसी वस्तु को क्लोन करते हैं जिसमें एक फ़ंक्शन होता है जो फ़ंक्शन खो जाएगा ..
पीटर

38

JSON.parse(JSON.stringify())के रूप में यह JSON डेटा के लिए चाहिए था गहरी प्रतिलिपि JavaScript ऑब्जेक्ट में संयोजन, एक अप्रभावी हैक है। यह के मूल्यों का समर्थन नहीं करता undefinedया function () {}, और बस उन्हें (या अनदेखी करेंगे nullउन्हें) जब "stringifying" (मार्शलिंग) JSON में जावास्क्रिप्ट वस्तु।

एक बेहतर समाधान एक गहरी प्रतिलिपि फ़ंक्शन का उपयोग करना है। डीप कॉपी ऑब्जेक्ट्स के नीचे का फंक्शन, और इसमें 3rd पार्टी लाइब्रेरी (jQuery, LoDash, आदि) की आवश्यकता नहीं होती है।

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

7
सिवाय इसके कि जब ऑबजेक्ट (या इसमें कोई अन्य वस्तु शामिल हो) में स्वयं का एक संदर्भ होता है ... stackoverflow ™!
e2-e4

@ ringø - क्या आप कुछ "सेल्फ रेफरेंस" टेस्ट केस दे सकते हैं?
tfmontague

4
var o = { a:1, b:2 } ; o["oo"] = { c:3, m:o };
e2-e4

4
मुझे यह समाधान पसंद है। मेरे लिए केवल फिक्स अशक्त मूल्यों के साथ काम कर रहा था: bObject[k] = (v === null) ? null : (typeof v === "object") ? copy(v) : v;
डेविड किर्कलैंड

2
यह फ़ंक्शन सरल, समझने योग्य है और लगभग सभी मामलों को पकड़ लेगा। जावास्क्रिप्ट दुनिया में आप के रूप में के रूप में सही है के रूप में आप प्राप्त कर सकते हैं।
icc97

21

यहाँ एक ES6 फ़ंक्शन है जो चक्रीय संदर्भ वाली वस्तुओं के लिए भी काम करेगा:

function deepClone(obj, hash = new WeakMap()) {
    if (Object(obj) !== obj) return obj; // primitives
    if (hash.has(obj)) return hash.get(obj); // cyclic reference
    const result = obj instanceof Set ? new Set(obj) // See note about this!
                 : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => 
                                        [key, deepClone(val, hash)])) 
                 : obj instanceof Date ? new Date(obj)
                 : obj instanceof RegExp ? new RegExp(obj.source, obj.flags)
                 // ... add here any specific treatment for other classes ...
                 // and finally a catch-all:
                 : obj.constructor ? new obj.constructor() 
                 : Object.create(null);
    hash.set(obj, result);
    return Object.assign(result, ...Object.keys(obj).map(
        key => ({ [key]: deepClone(obj[key], hash) }) ));
}

// Sample data
var p = {
  data: 1,
  children: [{
    data: 2,
    parent: null
  }]
};
p.children[0].parent = p;

var q = deepClone(p);

console.log(q.children[0].parent.data); // 1

सेट्स और मैप्स के बारे में एक नोट

कैसे सेट तथा मानचित्र की कुंजी के साथ निपटने के लिए बहस का मुद्दा है: उन कुंजियों को अक्सर पुरातन (इस स्थिति में कोई बहस नहीं है) हैं, लेकिन वे कर सकते हैं भी वस्तुओं हो। उस मामले में सवाल यह बन जाता है: क्या उन चाबियों को क्लोन किया जाना चाहिए?

कोई यह तर्क दे सकता है कि ऐसा किया जाना चाहिए, ताकि यदि उन वस्तुओं को कॉपी में उत्परिवर्तित किया जाता है, तो मूल में वस्तुएं प्रभावित नहीं होती हैं, और इसके विपरीत।

दूसरी ओर, कोई चाहेगा कि यदि सेट / मैप hasएक कुंजी है, तो यह मूल और प्रतिलिपि दोनों में सही होना चाहिए - कम से कम इससे पहले कि दोनों में से कोई भी परिवर्तन किया जाए। यह अजीब होगा यदि प्रतिलिपि एक सेट / मैप होगी जिसमें चाबियाँ हैं जो पहले कभी नहीं हुईं (जैसा कि वे क्लोनिंग प्रक्रिया के दौरान बनाई गई थीं): निश्चित रूप से यह किसी भी कोड के लिए बहुत उपयोगी नहीं है जो यह जानना आवश्यक है कि क्या दी गई वस्तु एक है उस सेट / मैप में कुंजी है या नहीं।

जैसा कि आप नोटिस करते हैं, मैं दूसरी राय से अधिक हूं: सेट और मैप्स की कुंजी मान हैं (शायद संदर्भ ) जो समान रहना चाहिए।

इस तरह की पसंद अक्सर अन्य (शायद कस्टम) वस्तुओं के साथ भी सतह होगी। कोई सामान्य समाधान नहीं है, जितना कि इस बात पर निर्भर करता है कि आपके विशिष्ट मामले में क्लोन किए गए ऑब्जेक्ट के व्यवहार की उम्मीद है।


तारीख और regexp को संभाल नहीं करता है
mkeremguc

1
@mkeremguc, आपकी टिप्पणी के लिए धन्यवाद। मैंने समर्थन दिनांक और regexp के लिए कोड को अपडेट किया।
त्रिनकोट

नक्शे सहित अच्छा समाधान। बस es6 सेट क्लोनिंग के लिए लापता समर्थन।
रॉबर्ट बिग्स

अगर मैं गलत नहीं हूं, तो आप शायद सेट के लिए समर्थन जोड़ सकते हैं:if (object instanceof Set) Array.from(object, val => result.add(deepClone(val, hash)));
रॉबर्ट बिग्स

@RobertBiggs, यह एक संभावना है, लेकिन मेरी राय में अगर किसी सेट की एक निश्चित कुंजी है, तो उस सेट के क्लोन संस्करण में भी सही होना चाहिए। आपके सुझाए गए कोड के साथ यह सही नहीं होगा यदि कुंजी ऑब्जेक्ट हैं। इसलिए मैं सुझाव दूंगा कि मैं चाबियों का क्लोनिंग नहीं करूंगा - मुझे वास्तव में लगता है कि यह फिर अपेक्षा के अनुरूप व्यवहार करेगा। उस संबंध में मेरे उत्तर का अद्यतन देखें।
त्रिकोट

10

Underscore.js योगदान पुस्तकालय पुस्तकालय में एक समारोह में कहा जाता है स्नैपशॉट गहरी क्लोन एक वस्तु है कि

स्रोत से स्निपेट:

snapshot: function(obj) {
  if(obj == null || typeof(obj) != 'object') {
    return obj;
  }

  var temp = new obj.constructor();

  for(var key in obj) {
    if (obj.hasOwnProperty(key)) {
      temp[key] = _.snapshot(obj[key]);
    }
  }

  return temp;
}

एक बार लाइब्रेरी आपके प्रोजेक्ट से जुड़ी होने के बाद, फंक्शन को बस यूज करें

_.snapshot(object);

4
अच्छा समाधान, याद रखने के लिए सिर्फ एक बिंदु: क्लोन और मूल समान प्रोटोटाइप साझा करते हैं। अगर यह एक समस्या है कि "temp .__ proto__ = .snapshot (obj .__ proto )) जोड़ना संभव है ;" "वापसी अस्थायी" के ठीक ऊपर, और 'नो एन्यूमरेट' के रूप में चिह्नित संपत्तियों के साथ बिल्ड-इन कक्षाओं का समर्थन करने के लिए आप "के लिए getOwnPropertyNames () के बजाय" पर (obj में var कुंजी) "
Ronn Ness

3

यह गहरी क्लोनिंग विधि है जिसका मैं उपयोग करता हूं, मुझे लगता है कि यह बहुत अच्छा है, आशा है कि आप सुझाव देंगे

function deepClone (obj) {
    var _out = new obj.constructor;

    var getType = function (n) {
        return Object.prototype.toString.call(n).slice(8, -1);
    }

    for (var _key in obj) {
        if (obj.hasOwnProperty(_key)) {
            _out[_key] = getType(obj[_key]) === 'Object' || getType(obj[_key]) === 'Array' ? deepClone(obj[_key]) : obj[_key];
        }
    }
    return _out;
}

3

जैसा कि अन्य लोगों ने इस और इसी तरह के सवालों पर ध्यान दिया है, सामान्य अर्थ में, एक "ऑब्जेक्ट" क्लोनिंग, जावास्क्रिप्ट में संदिग्ध है।

हालांकि, वस्तुओं का एक वर्ग है, जिसे मैं "डेटा" ऑब्जेक्ट कहता हूं, जो कि केवल { ... }शाब्दिक और / या साधारण संपत्ति असाइनमेंट से निर्मित हैं या JSON से deserialized हैं, जिसके लिए क्लोन करना चाहते हैं। बस आज मैं एक सर्वर से प्राप्त डेटा को कृत्रिम रूप से फुलाकर बड़ा करना चाहता था ताकि यह पता लगाया जा सके कि बड़े डेटा सेट के लिए क्या होता है, लेकिन ऑब्जेक्ट (एक सरणी) और उसके बच्चों को चीजों को सही ढंग से काम करने के लिए अलग-अलग ऑब्जेक्ट होना चाहिए। क्लोनिंग ने मुझे अपना डेटा सेट गुणा करने के लिए ऐसा करने की अनुमति दी:

return dta.concat(clone(dta),clone(dta),clone(dta),clone(dta));

दूसरी जगह जो मैं अक्सर डेटा ऑब्जेक्ट क्लोनिंग करता हूं वह होस्ट को डेटा वापस सबमिट करने के लिए है, जहां मैं भेजने से पहले डेटा मॉडल में ऑब्जेक्ट से राज्य फ़ील्ड को स्ट्रिप करना चाहता हूं। उदाहरण के लिए, मैं ऑब्जेक्ट से "_" से शुरू होने वाले सभी फ़ील्ड्स को पट्टी करना चाहता हूं क्योंकि यह क्लोन किया गया है।

यह वह कोड है जिसे मैंने यह लिखने के लिए उदारतापूर्वक करने के लिए लिखा था, जिसमें सहायक सरणियों और एक चयनकर्ता भी शामिल है, जिसे चुनने के लिए सदस्यों को क्लोन (जो संदर्भ निर्धारित करने के लिए "पथ" स्ट्रिंग का उपयोग करता है):

function clone(obj,sel) {
    return (obj ? _clone("",obj,sel) : obj);
    }

function _clone(pth,src,sel) {
    var ret=(src instanceof Array ? [] : {});

    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }

        var val=src[key], sub;

        if(sel) {
            sub+=pth+"/"+key;
            if(!sel(sub,key,val)) { continue; }
            }

        if(val && typeof(val)=='object') {
            if     (val instanceof Boolean) { val=Boolean(val);        }
            else if(val instanceof Number ) { val=Number (val);        }
            else if(val instanceof String ) { val=String (val);        }
            else                            { val=_clone(sub,val,sel); }
            }
        ret[key]=val;
        }
    return ret;
    }

गैर-मूल रूट ऑब्जेक्ट को मानते हुए और बिना किसी सदस्य के चयन के सबसे सरल उचित गहरा-क्लोन समाधान है:

function clone(src) {
    var ret=(src instanceof Array ? [] : {});
    for(var key in src) {
        if(!src.hasOwnProperty(key)) { continue; }
        var val=src[key];
        if(val && typeof(val)=='object') { val=clone(val);  }
        ret[key]=val;
        }
    return ret;
    }

2

लो-डैश , जो अब अंडरस्कोर।जेएस का सुपरसेट है , में कुछ गहरे क्लोन कार्य हैं:

एक से लेखक की जवाब खुद:

lodash underscore अंडरस्कोर के नवीनतम स्थिर संस्करण के साथ संगतता सुनिश्चित करने के लिए बिल्ड प्रदान किया गया है।


प्रश्न ने कहा "मैं पुस्तकालयों का उपयोग नहीं करना चाहता"
फेम ओनी

@FemiOni में पुस्तकालयों के बारे में कुछ भी नहीं है (यहां तक ​​कि इसके पुराने संपादनों में भी) ... कुछ अन्य उत्तर यहां एक पुस्तकालय या दूसरे का भी उपयोग कर रहे हैं।
CPHPython

@FemiOni ने कल जवाब दिया। मुझे आश्चर्य है ... वैसे भी, यह एक सीखने की जगह है और सिर्फ अगर कोई वास्तव में गहरे क्लोन को लागू करने जा रहा है, तो लॉश स्रोत कोडbaseClone कुछ विचार प्रदान कर सकता है।
CPHPython

@FemiOni JSON ऑब्जेक्ट न तो एक लाइब्रेरी है और न ही कोई फ्रेमवर्क ... यदि आप फ़ंक्शन को कार्यान्वित करने जा रहे हैं, तो मेरा सुझाव है कि आप ओपन सोर्स लाइब्रेरी में से एक में देखें और उन भागों का उपयोग करें जिनकी आपको ज़रूरत है (कई वर्षों से परीक्षण किया गया है)। यह लंबी अवधि में बग और छूटे हुए विचारों से बचेगा।
CPHPython 19

2

नीचे दी गई कार्यवृद्धि जावास्क्रिप्ट वस्तुओं को गहरी क्लोन करने का सबसे कारगर तरीका है।

function deepCopy(obj){
    if (!obj || typeof obj !== "object") return obj;

    var retObj = {};

    for (var attr in obj){
        var type = obj[attr];

        switch(true){
            case (type instanceof Date):
                var _d = new Date();
                _d.setDate(type.getDate())
                retObj[attr]= _d;
                break;

            case (type instanceof Function):
                retObj[attr]= obj[attr];
                break;

            case (type instanceof Array):
                var _a =[];
                for (var e of type){
                    //_a.push(e);
                    _a.push(deepCopy(e));
                }
                retObj[attr]= _a;
                break;

            case (type instanceof Object):
                var _o ={};
                for (var e in type){
                    //_o[e] = type[e];
                    _o[e] = deepCopy(type[e]);
                }
                retObj[attr]= _o;
                break;

            default:
                retObj[attr]= obj[attr];
        }
    }
    return retObj;
}

var obj = {
    string: 'test',
    array: ['1'],
    date: new Date(),
    object:{c: 2, d:{e: 3}},
    function: function(){
        return this.date;
    }
};

var copyObj = deepCopy(obj);

console.log('object comparison', copyObj === obj); //false
console.log('string check', copyObj.string === obj.string); //true
console.log('array check', copyObj.array === obj.array); //false
console.log('date check', copyObj2.date === obj.date); //false
console.log('object check', copyObj.object === obj.object); //false
console.log('function check', copyObj.function() === obj.function()); //true

2
क्या आपके पास अपने दावे का समर्थन करने के लिए कोई तर्क है?
फेबियन वॉन एलर्ट्स

मैंने फ़ंक्शन के नीचे एक उदाहरण दिया है। क्या तुम्हे कोई शक है?
कोल्डांडी

उन उदाहरणों से पता चलता है कि फ़ंक्शन काम कर रहा है, जो शांत है लेकिन यह "सबसे कुशल तरीका" क्यों है?
फेबियन वॉन एलर्ट्स

क्योंकि यह एकल लूप में ऑब्जेक्ट की विशेषताओं की पुनरावृत्ति कर रहा है। इसके अलावा दिनांक, कार्य, वस्तु, सरणी, संख्या, स्ट्रिंग सभी चरणों को ठीक से संभाला जाता है। क्या आपके पास कोई और रास्ता है?
कोल्डेंडी

2

अब ऐसे कार्य के लिए वास्तविक दुनिया की जरूरत नहीं होनी चाहिए। यह महज अकादमिक हित है।

विशुद्ध रूप से एक अभ्यास के रूप में, यह इसे करने का एक अधिक कार्यात्मक तरीका है। जैसा कि मैंने सुझाव दिया है कि यह वहां एक गार्ड ब्लॉक जोड़ने का सुझाव है @ @ tfmontague का विस्तार है । लेकिन जैसा कि मुझे लगता है कि मैं ES6 के लिए मजबूर हूं और सभी चीजों को देखता हूं, तो यहां मेरा बहुत अच्छा संस्करण है। यह तर्क को जटिल करता है क्योंकि आपको सरणी पर मैप करना होगा और ऑब्जेक्ट पर कम करना होगा, लेकिन यह किसी भी म्यूटेशन से बचा जाता है।

const cloner = (x) => {
    const recurseObj = x => (typeof x === 'object') ? cloner(x) : x
    const cloneObj = (y, k) => {
        y[k] = recurseObj(x[k])
        return y
    }
    // Guard blocks
    // Add extra for Date / RegExp if you want
    if (!x) {
        return x
    }
    if (Array.isArray(x)) {
        return x.map(recurseObj)
    }
    return Object.keys(x).reduce(cloneObj, {})
}
const tests = [
    null,
    [],
    {},
    [1,2,3],
    [1,2,3, null],
    [1,2,3, null, {}],
    [new Date('2001-01-01')], // FAIL doesn't work with Date
    {x:'', y: {yx: 'zz', yy: null}, z: [1,2,3,null]},
    {
        obj : new function() {
            this.name = "Object test";
        }
    } // FAIL doesn't handle functions
]
tests.map((x,i) => console.log(i, cloner(x)))


1

मैंने देखा कि मानचित्र को विशेष उपचार की आवश्यकता है, इस प्रकार इस धागे में सभी सुझावों के साथ, कोड होगा:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

1

मेरे सभी उत्तरों के अलावा

deepCopy = arr => {
  if (typeof arr !== 'object') return arr
  if(arr.pop) return [...arr].map(deepCopy)
  const copy = {}
  for (let prop in arr)
    copy[prop] = deepCopy(arr[prop])
  return copy
}

0

यह सरणियों, वस्तुओं और आदिम के लिए काम करता है। दोहरी पुनरावर्ती एल्गोरिथ्म जो दो ट्रैवर्सल विधियों के बीच स्विच करता है:

const deepClone = (objOrArray) => {

  const copyArray = (arr) => {
    let arrayResult = [];
    arr.forEach(el => {
        arrayResult.push(cloneObjOrArray(el));
    });
    return arrayResult;
  }

  const copyObj = (obj) => {
    let objResult = {};
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        objResult[key] = cloneObjOrArray(obj[key]);
      }
    }
    return objResult;
  }

  const cloneObjOrArray = (el) => {
    if (Array.isArray(el)) {
      return copyArray(el);
    } else if (typeof el === 'object') {
      return copyObj(el);
    } else {
      return el;
    }
  }

  return cloneObjOrArray(objOrArray);
}

0

डीपकोपी बनाने के लिए हम पुनरावृत्ति का उपयोग कर सकते हैं। यह फ़ंक्शन के साथ एरे, ऑब्जेक्ट, एरे ऑफ़ ऑब्जेक्ट, ऑब्जेक्ट की कॉपी बना सकता है। यदि आप चाहें, तो आप अन्य प्रकार के डेटा संरचना जैसे मानचित्र आदि के लिए फ़ंक्शन जोड़ सकते हैं।

function deepClone(obj) {
         var retObj;
        _assignProps = function(obj, keyIndex, retObj) {
               var subType = Object.prototype.toString.call(obj[keyIndex]);
               if(subType === "[object Object]" || subType === "[object Array]") {
                    retObj[keyIndex] = deepClone(obj[keyIndex]);
               }
               else {
                     retObj[keyIndex] = obj[keyIndex];
               }
        };

        if(Object.prototype.toString.call(obj) === "[object Object]") {
           retObj = {};
           for(key in obj) {
               this._assignProps(obj, key, retObj);
           }
        }
        else if(Object.prototype.toString.call(obj) == "[object Array]") {
           retObj = [];
           for(var i = 0; i< obj.length; i++) {
              this._assignProps(obj, i, retObj);
            }
        };

        return retObj;
    };

0

ImmutableJS का उपयोग करें

import { fromJS } from 'immutable';

// An object we want to clone
let objA = { 
   a: { deep: 'value1', moreDeep: {key: 'value2'} } 
};

let immB = fromJS(objA); // Create immutable Map
let objB = immB.toJS(); // Convert to plain JS object

console.log(objA); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }
console.log(objB); // Object { a: { deep: 'value1', moreDeep: {key: 'value2'} } }

// objA and objB are equalent, but now they and their inner objects are undependent
console.log(objA === objB); // false
console.log(objA.a === objB.a); // false
console.log(objA.moreDeep === objB.moreDeep); // false

या लॉज / मर्ज

import merge from 'lodash/merge'

var objA = {
    a: [{ 'b': 2 }, { 'd': 4 }]
};
// New deeply cloned object:
merge({}, objA ); 

// We can also create new object from several objects by deep merge:
var objB = {
    a: [{ 'c': 3 }, { 'e': 5 }]
};
merge({}, objA , objB ); // Object { a: [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }

0

यह एक, परिपत्र संदर्भ का उपयोग करते हुए, मेरे लिए काम करता है

 //a test-object with circular reference :
 var n1 = {   id:0,   text:"aaaaa",   parent:undefined} 
 var n2 = {  id:1,   text:"zzzzz",   parent:undefined } 
 var o = { arr:[n1,n2],   parent:undefined } 
 n1.parent = n2.parent = o;
 var obj = {   a:1,   b:2,   o:o }
 o.parent = obj;

 function deepClone(o,output){ 

     if(!output) output = {};  
     if(o.______clone) return o.______clone;
     o.______clone = output.______clone = output;

   for(var z in o){

     var obj = o[z];
     if(typeof(obj) == "object") output[z] = deepClone(obj)
     else output[z] = obj; 
    }

   return output;
}

console.log(deepClone(obj));

0

var newDate = नई तिथि (this.oldDate); मैं फ़ंक्शन करने के लिए oldDate पास कर रहा था और इस से newDate जेनरेट कर रहा था। लेकिन यह इस बदल रहा था।


0

इस समाधान का उपयोग करते समय पुनरावृत्ति की समस्याओं से बचना होगा [... लक्ष्य] या {... लक्ष्य}

function shallowClone(target) {
  if (typeof a == 'array') return [...target]
  if (typeof a == 'object') return {...target}
  return target
}

/* set skipRecursion to avoid throwing an exception on recursive references */
/* no need to specify refs, or path -- they are used interally */
function deepClone(target, skipRecursion, refs, path) {
  if (!refs) refs = []
  if (!path) path = ''
  if (refs.indexOf(target) > -1) {
    if (skipRecursion) return null
    throw('Recursive reference at ' + path)
  }
  refs.push(target)
  let clone = shallowCopy(target)
  for (i in target) target[i] = deepClone(target, refs, path + '.' + i)
  return clone
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.