javascript - जावास्क्रिप्ट में एक वस्तु गहरी क्लोन करने का सबसे प्रभावी तरीका क्या है?




object clone (25)

जावास्क्रिप्ट ऑब्जेक्ट क्लोन करने का सबसे प्रभावी तरीका क्या है? मैंने obj = eval(uneval(o)); इस्तेमाल किया जा रहा है, लेकिन यह गैर मानक है और केवल फ़ायरफ़ॉक्स द्वारा समर्थित है

मैंने obj = JSON.parse(JSON.stringify(o)); जैसी चीजें की हैं obj = JSON.parse(JSON.stringify(o)); लेकिन दक्षता पर सवाल उठाओ।

मैंने विभिन्न त्रुटियों के साथ रिकर्सिव कॉपीिंग फ़ंक्शंस भी देखा है।
मुझे आश्चर्य है कि कोई कैनोलिक समाधान मौजूद नहीं है।


Answers

यदि कोई अंतर्निहित नहीं था, तो आप कोशिश कर सकते हैं:

function clone(obj) {
    if (obj === null || typeof (obj) !== 'object' || 'isActiveClone' in obj)
        return obj;

    if (obj instanceof Date)
        var temp = new obj.constructor(); //or new Date(obj);
    else
        var temp = obj.constructor();

    for (var key in obj) {
        if (Object.prototype.hasOwnProperty.call(obj, key)) {
            obj['isActiveClone'] = null;
            temp[key] = clone(obj[key]);
            delete obj['isActiveClone'];
        }
    }
    return temp;
}

क्रॉकफ़ोर्ड इस फ़ंक्शन का उपयोग करके सुझाता है (और मुझे पसंद है):

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

var newObject = object(oldObject);

यह terse है, उम्मीद के रूप में काम करता है और आपको पुस्तकालय की आवश्यकता नहीं है।

संपादित करें:

यह एक पॉलीफिल है Object.create, इसलिए आप इसका भी उपयोग कर सकते हैं।

var newObject = Object.create(oldObject);

नोट: यदि आप इनमें से कुछ का उपयोग करते हैं, तो आपको कुछ पुनरावृत्ति के साथ समस्या हो सकती है जो उपयोग करते हैं hasOwnProperty। क्योंकि, createविरासत में आने वाली नई खाली वस्तु बनाएं oldObject। लेकिन यह क्लोनिंग ऑब्जेक्ट्स के लिए अभी भी उपयोगी और व्यावहारिक है।

उदाहरण के लिए अगर oldObject.a = 5;

newObject.a; // is 5

परंतु:

oldObject.hasOwnProperty(a); // is true
newObject.hasOwnProperty(a); // is false

शैल कॉपी एक लाइनर ( ईसीएमएस्क्रिप्ट 5 वां संस्करण ):

var origin = { foo : {} };
var copy = Object.keys(origin).reduce(function(c,k){c[k]=origin[k];return c;},{});

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

और उथले प्रतिलिपि एक लाइनर ( ईसीएमएस्क्रिप्ट 6 वां संस्करण , 2015):

var origin = { foo : {} };
var copy = Object.assign({}, origin);

console.log(origin, copy);
console.log(origin == copy); // false
console.log(origin.foo == copy.foo); // true

कोंनोय के उत्तर का एक संस्करण यहां दिया गया है जो कि कन्स्ट्रक्टर के पैरामीटर की आवश्यकता होने पर भी काम करता है:

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

function deepCopy(obj) {
    if(obj == null || typeof(obj) !== 'object'){
        return obj;
    }
    //make sure the returned object has the same prototype as the original
    var ret = object_create(obj.constructor.prototype);
    for(var key in obj){
        ret[key] = deepCopy(obj[key]);
    }
    return ret;
}

यह फ़ंक्शन मेरी simpleoo पुस्तकालय में भी उपलब्ध है ।

संपादित करें:

यहां एक और मजबूत संस्करण है (जस्टिन मैककंडलेस के लिए धन्यवाद, यह अब चक्रीय संदर्भों का भी समर्थन करता है):

/**
 * Deep copy an object (make copies of all its object properties, sub-properties, etc.)
 * An improved version of http://keithdevens.com/weblog/archive/2007/Jun/07/javascript.clone
 * that doesn't break if the constructor has required parameters
 * 
 * It also borrows some code from http://.com/a/11621004/560114
 */ 
function deepCopy(src, /* INTERNAL */ _visited, _copiesVisited) {
    if(src === null || typeof(src) !== 'object'){
        return src;
    }

    //Honor native/custom clone methods
    if(typeof src.clone == 'function'){
        return src.clone(true);
    }

    //Special cases:
    //Date
    if(src instanceof Date){
        return new Date(src.getTime());
    }
    //RegExp
    if(src instanceof RegExp){
        return new RegExp(src);
    }
    //DOM Element
    if(src.nodeType && typeof src.cloneNode == 'function'){
        return src.cloneNode(true);
    }

    // Initialize the visited objects arrays if needed.
    // This is used to detect cyclic references.
    if (_visited === undefined){
        _visited = [];
        _copiesVisited = [];
    }

    // Check if this object has already been visited
    var i, len = _visited.length;
    for (i = 0; i < len; i++) {
        // If so, get the copy we already made
        if (src === _visited[i]) {
            return _copiesVisited[i];
        }
    }

    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice() by itself would soft clone
        var ret = src.slice();

        //add it to the visited array
        _visited.push(src);
        _copiesVisited.push(ret);

        var i = ret.length;
        while (i--) {
            ret[i] = deepCopy(ret[i], _visited, _copiesVisited);
        }
        return ret;
    }

    //If we've reached here, we have a regular object

    //make sure the returned object has the same prototype as the original
    var proto = (Object.getPrototypeOf ? Object.getPrototypeOf(src): src.__proto__);
    if (!proto) {
        proto = src.constructor.prototype; //this line would probably only be reached by very old browsers 
    }
    var dest = object_create(proto);

    //add this object to the visited array
    _visited.push(src);
    _copiesVisited.push(dest);

    for (var key in src) {
        //Note: this does NOT preserve ES5 property attributes like 'writable', 'enumerable', etc.
        //For an example of how this could be modified to do so, see the singleMixin() function
        dest[key] = deepCopy(src[key], _visited, _copiesVisited);
    }
    return dest;
}

//If Object.create isn't already defined, we just do the simple shim,
//without the second argument, since that's all we need here
var object_create = Object.create;
if (typeof object_create !== 'function') {
    object_create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}

मुझे पता है कि यह एक पुरानी पोस्ट है, लेकिन मैंने सोचा कि यह अगले व्यक्ति को कुछ मदद की जा सकती है जो साथ में ठोकर खाती है।

जब तक आप किसी ऑब्जेक्ट को किसी ऑब्जेक्ट को असाइन नहीं करते हैं, तब तक यह स्मृति में कोई संदर्भ नहीं रखता है। तो एक ऑब्जेक्ट बनाने के लिए जिसे आप अन्य ऑब्जेक्ट्स के बीच साझा करना चाहते हैं, आपको इस तरह का एक कारखाना बनाना होगा:

var a = function(){
    return {
        father:'zacharias'
    };
},
b = a(),
c = a();
c.father = 'johndoe';
alert(b.father);

var clone = function() {
    var newObj = (this instanceof Array) ? [] : {};
    for (var i in this) {
        if (this[i] && typeof this[i] == "object") {
            newObj[i] = this[i].clone();
        }
        else
        {
            newObj[i] = this[i];
        }
    }
    return newObj;
}; 

Object.defineProperty( Object.prototype, "clone", {value: clone, enumerable: false});

प्रदर्शन द्वारा गहरी प्रतिलिपि: सबसे खराब से सबसे खराब स्थान पर

  • पुन: असाइनमेंट "=" (स्ट्रिंग सरणी, संख्या सरणी - केवल)
  • स्लाइस (स्ट्रिंग सरणी, संख्या सरणी - केवल)
  • Concatenation (स्ट्रिंग सरणी, संख्या सरणी - केवल)
  • कस्टम फ़ंक्शन: फॉर-लूप या रिकर्सिव कॉपी
  • jQuery का $ .extend
  • JSON.parse (स्ट्रिंग सरणी, संख्या सरणी, ऑब्जेक्ट सरणी - केवल)
  • Underscore.js _ _clone (स्ट्रिंग सरणी, संख्या सरणी - केवल)
  • लो-डैश का _.cloneDeep

गहरी तारों या संख्याओं की एक सरणी प्रतिलिपि बनाएँ (एक स्तर - कोई संदर्भ पॉइंटर्स):

जब किसी सरणी में संख्याएं और तार होते हैं - .slice (), .concat (), .splice (), असाइनमेंट ऑपरेटर "=", और Underscore.js के क्लोन फ़ंक्शन जैसे फ़ंक्शन; सरणी के तत्वों की गहरी प्रतिलिपि बनायेगा।

जहां पुन: असाइनमेंट में सबसे तेज़ प्रदर्शन है:

var arr1 = ['a', 'b', 'c'];
var arr2 = arr1;
arr1 = ['a', 'b', 'c'];

और .slice () में .concat (), http://jsperf.com/duplicate-array-slice-vs-concat/3 से बेहतर प्रदर्शन है

var arr1 = ['a', 'b', 'c'];  // Becomes arr1 = ['a', 'b', 'c']
var arr2a = arr1.slice(0);   // Becomes arr2a = ['a', 'b', 'c'] - deep copy
var arr2b = arr1.concat();   // Becomes arr2b = ['a', 'b', 'c'] - deep copy

गहरी वस्तुओं की एक सरणी प्रतिलिपि बनाएँ (दो या अधिक स्तर - संदर्भ पॉइंटर्स):

var arr1 = [{object:'a'}, {object:'b'}];

एक कस्टम फ़ंक्शन लिखें ($ .extend () या JSON.parse से तेज़ प्रदर्शन है):

function copy(o) {
   var out, v, key;
   out = Array.isArray(o) ? [] : {};
   for (key in o) {
       v = o[key];
       out[key] = (typeof v === "object" && v !== null) ? copy(v) : v;
   }
   return out;
}

copy(arr1);

तृतीय-पक्ष उपयोगिता फ़ंक्शंस का उपयोग करें:

$.extend(true, [], arr1); // Jquery Extend
JSON.parse(arr1);
_.cloneDeep(arr1); // Lo-dash

जहां jQuery के $ .extend बेहतर प्रदर्शन है:


मैं here सबसे महान वोटों के साथ जवाब से असहमत हूं । एक रिकर्सिव दीप क्लोन है बहुत तेजी से JSON.parse (JSON.stringify (obj)) दृष्टिकोण का उल्लेख किया।

  • जेस्परफ इसे यहां नंबर एक स्थान पर रखता है: https://jsperf.com/deep-copy-vs-json-stringify-json-parse/5
  • ऊपर दिए गए उत्तर से जेएसबेन यह दिखाने के लिए अपडेट किया गया है कि एक रिकर्सिव गहरे क्लोन का उल्लेख अन्य सभी को मारता है: http://jsben.ch/13YKQ

और यहां त्वरित संदर्भ के लिए कार्य है:

function cloneDeep (o) {
  let newO
  let i

  if (typeof o !== 'object') return o

  if (!o) return o

  if (Object.prototype.toString.apply(o) === '[object Array]') {
    newO = []
    for (i = 0; i < o.length; i += 1) {
      newO[i] = cloneDeep(o[i])
    }
    return newO
  }

  newO = {}
  for (i in o) {
    if (o.hasOwnProperty(i)) {
      newO[i] = cloneDeep(o[i])
    }
  }
  return newO
}

मेरे पास "सादे पुराने जावास्क्रिप्ट ऑब्जेक्ट" को क्लोन करना है या नहीं, इस पर निर्भर करते हुए मेरे पास दो अच्छे उत्तर हैं।

आइए यह भी मान लें कि आपका इरादा स्रोत ऑब्जेक्ट पर वापस प्रोटोटाइप संदर्भों के साथ एक पूर्ण क्लोन बनाना है। यदि आप एक पूर्ण क्लोन में रूचि नहीं रखते हैं, तो आप कुछ अन्य उत्तरों (क्रॉकफ़ोर्ड के पैटर्न) में प्रदान की गई ऑब्जेक्ट.क्लोन () रूटीन का उपयोग कर सकते हैं।

सादे पुराने जावास्क्रिप्ट ऑब्जेक्ट्स के लिए, आधुनिक रनटाइम्स में किसी ऑब्जेक्ट को क्लोन करने का एक प्रयास किया गया और सही अच्छा तरीका काफी सरल है:

var clone = JSON.parse(JSON.stringify(obj));

ध्यान दें कि स्रोत ऑब्जेक्ट एक शुद्ध JSON ऑब्जेक्ट होना चाहिए। यह कहना है, इसके सभी घोंसले वाले गुण स्केलर (जैसे बुलियन, स्ट्रिंग, सरणी, ऑब्जेक्ट इत्यादि) होना चाहिए। RegExp या दिनांक जैसे किसी भी फ़ंक्शन या विशेष ऑब्जेक्ट को क्लोन नहीं किया जाएगा।

क्या यह कुशल है? धत्त हां। हमने सभी प्रकार की क्लोनिंग विधियों का प्रयास किया है और यह सबसे अच्छा काम करता है। मुझे यकीन है कि कुछ निंजा एक तेज विधि को स्वीकार कर सकते हैं। लेकिन मुझे संदेह है कि हम मामूली लाभ के बारे में बात कर रहे हैं।

यह दृष्टिकोण लागू करने के लिए बस सरल और आसान है। इसे एक सुविधाजनक समारोह में लपेटें और यदि आपको वास्तव में कुछ लाभ प्राप्त करने की आवश्यकता है, तो बाद में जाएं।

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

ऐसा करने का सही तरीका, एक बार फिर, एक सुविधाजनक विधि के माध्यम से है जिसे आप अपने कोड में घोषित करते हैं और पुन: उपयोग करते हैं। सुविधा विधि को अपनी वस्तुओं की कुछ समझ के साथ संपन्न किया जा सकता है ताकि आप नए ऑब्जेक्ट के भीतर ग्राफ को सही तरीके से पुनर्निर्मित कर सकें।

हम अपना खुद लिखा है, लेकिन मैंने देखा है कि सबसे अच्छा सामान्य दृष्टिकोण यहां शामिल है:

http://davidwalsh.name/javascript-clone

यह सही विचार है। लेखक (डेविड वॉल्श) ने सामान्यीकृत कार्यों के क्लोनिंग पर टिप्पणी की है। यह आपके द्वारा उपयोग किए जाने वाले मामले के आधार पर कुछ ऐसा करने का विकल्प चुन सकता है।

मुख्य विचार यह है कि आपको प्रति-प्रकार के आधार पर अपने कार्यों (या प्रोटोटाइप कक्षाओं, बोलने के लिए) के तत्कालता को विशेष रूप से संभालना होगा। यहां, उन्होंने RegExp और तिथि के लिए कुछ उदाहरण प्रदान किए हैं।

न केवल यह कोड संक्षिप्त है, बल्कि यह भी बहुत पठनीय है। विस्तार करना बहुत आसान है।

क्या यह कुशल है? धत्त हां। यह देखते हुए कि लक्ष्य एक वास्तविक गहरे प्रतिलिपि क्लोन का उत्पादन करना है, तो आपको स्रोत ऑब्जेक्ट ग्राफ़ के सदस्यों को चलना होगा। इस दृष्टिकोण के साथ, आप वास्तव में किस प्रकार के बच्चे के सदस्यों से इलाज कर सकते हैं और मैन्युअल रूप से कस्टम प्रकारों को कैसे प्रबंधित कर सकते हैं।

तो यह तूम गए वहाँ। दो दृष्टिकोण दोनों मेरे विचार में कुशल हैं।


मैं यही उपयोग कर रहा हूं:

function cloneObject(obj) {
    var clone = {};
    for(var i in obj) {
        if(typeof(obj[i])=="object" && obj[i] != null)
            clone[i] = cloneObject(obj[i]);
        else
            clone[i] = obj[i];
    }
    return clone;
}

AngularJS

ठीक है अगर आप कोणीय का उपयोग कर रहे हैं तो आप भी ऐसा कर सकते हैं

var newObject = angular.copy(oldObject);

किसी ऑब्जेक्ट को Cloning करना हमेशा जेएस में चिंता का विषय था, लेकिन यह सब ईएस 6 से पहले था, मैं नीचे जावास्क्रिप्ट में ऑब्जेक्ट की प्रतिलिपि बनाने के विभिन्न तरीकों की सूची देता हूं, कल्पना करें कि आपके पास नीचे ऑब्जेक्ट है और इसकी गहरी प्रतिलिपि बनाना चाहेंगे:

var obj = {a:1, b:2, c:3, d:4};

उत्पत्ति को बदलने के बिना, इस ऑब्जेक्ट को कॉपी करने के कुछ तरीके हैं:

1) ES5 +, आपके लिए प्रतिलिपि करने के लिए एक साधारण फ़ंक्शन का उपयोग करना:

function deepCopyObj(obj) {
    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 this object.");
}

2) ES5 +, JSON.parse और JSON.stringify का उपयोग कर।

var  deepCopyObj = JSON.parse(JSON.stringify(obj));

3) कोणीय जेएस:

var  deepCopyObj = angular.copy(obj);

4) jQuery:

var deepCopyObj = jQuery.extend(true, {}, obj);

5) अंडरस्कोर जेएस और लोडैश:

var deepCopyObj = _.cloneDeep(obj); //latest version UndescoreJs makes shallow copy

आशा है कि ये मदद ...


यह आम तौर पर सबसे कुशल समाधान नहीं है, लेकिन यह वही करता है जो मुझे चाहिए। नीचे सरल परीक्षण मामले ...

function clone(obj, clones) {
    // Makes a deep copy of 'obj'. Handles cyclic structures by
    // tracking cloned obj's in the 'clones' parameter. Functions 
    // are included, but not cloned. Functions members are cloned.
    var new_obj,
        already_cloned,
        t = typeof obj,
        i = 0,
        l,
        pair; 

    clones = clones || [];

    if (obj === null) {
        return obj;
    }

    if (t === "object" || t === "function") {

        // check to see if we've already cloned obj
        for (i = 0, l = clones.length; i < l; i++) {
            pair = clones[i];
            if (pair[0] === obj) {
                already_cloned = pair[1];
                break;
            }
        }

        if (already_cloned) {
            return already_cloned; 
        } else {
            if (t === "object") { // create new object
                new_obj = new obj.constructor();
            } else { // Just use functions as is
                new_obj = obj;
            }

            clones.push([obj, new_obj]); // keep track of objects we've cloned

            for (key in obj) { // clone object members
                if (obj.hasOwnProperty(key)) {
                    new_obj[key] = clone(obj[key], clones);
                }
            }
        }
    }
    return new_obj || obj;
}

चक्रीय सरणी परीक्षण ...

a = []
a.push("b", "c", a)
aa = clone(a)
aa === a //=> false
aa[2] === a //=> false
aa[2] === a[2] //=> false
aa[2] === aa //=> true

कार्य परीक्षण...

f = new Function
f.a = a
ff = clone(f)
ff === f //=> true
ff.a === a //=> false

एक पुस्तकालय (जिसे "क्लोन" कहा जाता है) है , जो यह काफी अच्छा करता है। यह सबसे पूर्ण रिकर्सिव क्लोनिंग / अनियंत्रित वस्तुओं की प्रतिलिपि प्रदान करता है जो मुझे पता है। यह परिपत्र संदर्भों का भी समर्थन करता है, जो अभी तक अन्य उत्तरों द्वारा कवर नहीं है।

आप इसे एनपीएम पर भी पा सकते हैं । इसका उपयोग ब्राउज़र के साथ-साथ Node.js. के लिए भी किया जा सकता है।

इसका उपयोग कैसे करें इसका एक उदाहरण यहां दिया गया है:

इसे स्थापित करें

npm install clone

या इसे Ender साथ पैकेज करें।

ender build clone [...]

आप मैन्युअल रूप से स्रोत कोड भी डाउनलोड कर सकते हैं।

फिर आप इसे अपने स्रोत कोड में उपयोग कर सकते हैं।

var clone = require('clone');

var a = { foo: { bar: 'baz' } };  // inital value of a
var b = clone(a);                 // clone a -> b
a.foo.bar = 'foo';                // change a

console.log(a);                   // { foo: { bar: 'foo' } }
console.log(b);                   // { foo: { bar: 'baz' } }

(अस्वीकरण: मैं पुस्तकालय का लेखक हूं।)


यहां एक व्यापक क्लोन () विधि है जो किसी भी जावास्क्रिप्ट ऑब्जेक्ट को क्लोन कर सकती है। यह लगभग सभी मामलों को संभालता है:

function clone(src, deep) {

    var toString = Object.prototype.toString;
    if (!src && typeof src != "object") {
        // Any non-object (Boolean, String, Number), null, undefined, NaN
        return src;
    }

    // Honor native/custom clone methods
    if (src.clone && toString.call(src.clone) == "[object Function]") {
        return src.clone(deep);
    }

    // DOM elements
    if (src.nodeType && toString.call(src.cloneNode) == "[object Function]") {
        return src.cloneNode(deep);
    }

    // Date
    if (toString.call(src) == "[object Date]") {
        return new Date(src.getTime());
    }

    // RegExp
    if (toString.call(src) == "[object RegExp]") {
        return new RegExp(src);
    }

    // Function
    if (toString.call(src) == "[object Function]") {

        //Wrap in another method to make sure == is not true;
        //Note: Huge performance issue due to closures, comment this :)
        return (function(){
            src.apply(this, arguments);
        });
    }

    var ret, index;
    //Array
    if (toString.call(src) == "[object Array]") {
        //[].slice(0) would soft clone
        ret = src.slice();
        if (deep) {
            index = ret.length;
            while (index--) {
                ret[index] = clone(ret[index], true);
            }
        }
    }
    //Object
    else {
        ret = src.constructor ? new src.constructor() : {};
        for (var prop in src) {
            ret[prop] = deep
                ? clone(src[prop], true)
                : src[prop];
        }
    }
    return ret;
};

नोट: यह किसी अन्य उत्तर का उत्तर है, इस प्रश्न का उचित जवाब नहीं। यदि आप तेजी से ऑब्जेक्ट क्लोनिंग करना चाहते हैं तो कृपया इस प्रश्न के उत्तर में कॉर्बान की सलाह का पालन ​​करें।

मैं ध्यान रखना चाहता हूं कि jQuery में .clone() विधि केवल क्लोन डीओएम तत्वों को क्लोन करता है। जावास्क्रिप्ट ऑब्जेक्ट्स क्लोन करने के लिए, आप करेंगे:

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

अधिक जानकारी jQuery दस्तावेज़ में पाया जा सकता है।

मैं यह भी ध्यान रखना चाहता हूं कि गहरी प्रति वास्तव में ऊपर दिखाए गए कार्यों की तुलना में बहुत अधिक स्मार्ट है - यह कई जाल से बचने में सक्षम है (उदाहरण के लिए, डीओएम तत्व को गहराई से बढ़ाने की कोशिश कर रहा है)। यह अक्सर jQuery कोर और प्लगइन में बहुत प्रभाव के लिए प्रयोग किया जाता है।


संरचित क्लोनिंग

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

ब्राउज़रों में प्रत्यक्ष समर्थन: जल्द ही आ रहा है? 🙂

ब्राउज़र वर्तमान में संरचित क्लोनिंग एल्गोरिदम के लिए प्रत्यक्ष इंटरफ़ेस प्रदान नहीं करते हैं, लेकिन गिटहब पर व्हाटवाग / एचटीएमएल # 793 में एक वैश्विक संरचित क्लोन structuredClone() फ़ंक्शन सक्रिय रूप से चर्चा की जा रही है और जल्द ही आ रही है! वर्तमान में प्रस्तावित, अधिकांश उद्देश्यों के लिए इसका उपयोग करना उतना आसान होगा जितना:

const clone = structuredClone(original);

जब तक यह शिप नहीं किया जाता है, ब्राउज़र के संरचित क्लोन कार्यान्वयन केवल अप्रत्यक्ष रूप से उजागर होते हैं।

असीमित वर्कअराउंड: उपयोग योग्य। 😕

मौजूदा एपीआई के साथ एक संरचित क्लोन बनाने के लिए निचले ओवरहेड तरीका संदेश MessageChannels एक बंदरगाह के माध्यम से डेटा पोस्ट करना है। दूसरा बंदरगाह संलग्न message संरचित क्लोन के साथ एक message घटना उत्सर्जित करेगा। दुर्भाग्यवश, इन घटनाओं को सुनना आवश्यक रूप से असीमित है, और तुल्यकालिक विकल्प कम व्यावहारिक हैं।

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;

    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;

    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

उदाहरण का प्रयोग करें:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));

  console.log("Assertions complete.");
};

main();

तुल्यकालिक कामकाज: भयानक! 🤢

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

history.pushState() और history.replaceState() दोनों अपने पहले तर्क के संरचित क्लोन बनाते हैं, और उस मान को history.state को असाइन करते हैं। आप इस तरह किसी ऑब्जेक्ट के संरचित क्लोन बनाने के लिए इसका उपयोग कर सकते हैं:

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

उदाहरण का प्रयोग करें:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

हालांकि तुल्यकालिक, यह बेहद धीमा हो सकता है। यह ब्राउजर इतिहास में हेरफेर करने के साथ जुड़े सभी ओवरहेड को घुमाता है। बार-बार इस विधि को कॉल करने से क्रोम अस्थायी रूप से अनुत्तरदायी हो सकता है।

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

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

उदाहरण का प्रयोग करें:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();


यह मानते हुए कि आपके पास केवल वेरिएबल हैं और आपके ऑब्जेक्ट में कोई फ़ंक्शन नहीं है, आप बस इसका उपयोग कर सकते हैं:

var newObject = JSON.parse(JSON.stringify(oldObject));

कोड की एक पंक्ति में एक ऑब्जेक्ट क्लोन (गहरे क्लोन नहीं) को क्लोन करने का प्रभावी तरीका

एक Object.assign विधि Object.assign 2015 (ईएस 6) मानक का हिस्सा है और आपको वही करता है जो आपको चाहिए।

var clone = Object.assign({}, obj);

ऑब्जेक्ट.साइन () विधि का प्रयोग एक या अधिक स्रोत ऑब्जेक्ट्स से लक्ष्य ऑब्जेक्ट पर सभी समृद्ध गुणों के मानों की प्रतिलिपि बनाने के लिए किया जाता है।

Object.assign

पुराने ब्राउज़रों का समर्थन करने के लिए पॉलीफिल :

if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}

जो लोग JSON.parse(JSON.stringify(obj))संस्करण का उपयोग करना चाहते हैं , उनके लिए डेट ऑब्जेक्ट्स खोए बिना, आप तारों को वापस दिनांक में बदलने के लिए विधि के दूसरे तर्क काparse उपयोग कर सकते हैं :

function clone(obj) {
  var regExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
  return JSON.parse(JSON.stringify(x), function(k, v) {
    if (typeof v === 'string' && regExp.test(v))
      return new Date(v);
    return v;
  });
}

इस बेंचमार्क को चेकआउट करें: http://jsben.ch/#/bWfk9

मेरे पिछले परीक्षणों में जहां गति एक मुख्य चिंता थी

JSON.parse(JSON.stringify(obj))

गहरी क्लोन को ऑब्जेक्ट का सबसे तेज़ तरीका बनने के लिए (यह 10-20% तक गहरा ध्वज सेट के साथ jQuery.extend को बाहर करता है)।

jQuery.extend बहुत तेज़ है जब गहरा ध्वज झूठा (उथला क्लोन) पर सेट होता है। यह एक अच्छा विकल्प है, क्योंकि इसमें टाइप प्रमाणीकरण के लिए कुछ अतिरिक्त तर्क शामिल हैं और अपरिभाषित गुणों आदि पर प्रतिलिपि नहीं है, लेकिन यह आपको थोड़ा धीमा कर देगा।

यदि आप उन ऑब्जेक्ट्स की संरचना को जानते हैं जिन्हें आप क्लोन करने की कोशिश कर रहे हैं या गहरे घोंसले वाले सरणी से बच सकते हैं, तो आप हैऑनप्रॉपर्टी की जांच करते समय अपनी ऑब्जेक्ट क्लोन करने के for (var i in obj) लूप के लिए एक सरल लिख सकते हैं और यह jQuery से बहुत तेज होगा।

आखिरकार यदि आप हॉट लूप में किसी ज्ञात ऑब्जेक्ट स्ट्रक्चर को क्लोन करने का प्रयास कर रहे हैं तो आप क्लोन प्रक्रिया को आसानी से अस्तर करके और ऑब्जेक्ट मैन्युअल रूप से निर्माण करके बहुत अधिक सटीकता प्राप्त कर सकते हैं।

जावास्क्रिप्ट ट्रेस इंजन for..in loops के अनुकूलन पर चूसते हैं और जांच की हैऑनप्रोपर्टी आपको भी धीमा कर देगी। गति पूर्ण होने पर मैन्युअल क्लोन।

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

Date वस्तुओं पर JSON.parse(JSON.stringify(obj)) विधि का उपयोग करके सावधान रहें - JSON.stringify(new Date()) आईएसओ प्रारूप में दिनांक की स्ट्रिंग प्रस्तुति देता है, जो JSON.parse() वापस परिवर्तित नहीं होता है एक Date वस्तु के लिए। अधिक जानकारी के लिए यह उत्तर देखें

इसके अतिरिक्त, कृपया ध्यान दें कि, क्रोम 65 में कम से कम, मूल क्लोनिंग जाने का तरीका नहीं है। इस जेएसपीएआरएफ के अनुसार, एक नया फ़ंक्शन बनाकर देशी क्लोनिंग करना JSON.stringify का उपयोग करने से लगभग 800x धीमी है जो बोर्ड भर में अविश्वसनीय रूप से तेज़ है।


सरणी जैसी वस्तुओं के लिए अभी तक कोई आदर्श गहरा क्लोन ऑपरेटर नहीं लगता है। जैसा कि नीचे दिया गया कोड दिखाता है, जॉन रेजिग का jQuery क्लोनर गैर-संख्यात्मक गुणों वाले सरणी को उन वस्तुओं में बदल देता है जो सरणी नहीं हैं, और RegDwight के JSON क्लोनर गैर-संख्यात्मक गुणों को छोड़ देता है। निम्नलिखित परीक्षण कई बिंदुओं पर इन बिंदुओं को चित्रित करते हैं:

function jQueryClone(obj) {
   return jQuery.extend(true, {}, obj)
}

function JSONClone(obj) {
   return JSON.parse(JSON.stringify(obj))
}

var arrayLikeObj = [[1, "a", "b"], [2, "b", "a"]];
arrayLikeObj.names = ["m", "n", "o"];
var JSONCopy = JSONClone(arrayLikeObj);
var jQueryCopy = jQueryClone(arrayLikeObj);

alert("Is arrayLikeObj an array instance?" + (arrayLikeObj instanceof Array) +
      "\nIs the jQueryClone an array instance? " + (jQueryCopy instanceof Array) +
      "\nWhat are the arrayLikeObj names? " + arrayLikeObj.names +
      "\nAnd what are the JSONClone names? " + JSONCopy.names)

निम्नलिखित एक ही वस्तु के दो उदाहरण बनाता है। मैंने इसे पाया और वर्तमान में इसका उपयोग कर रहा हूं। यह उपयोग करना आसान और आसान है।

var objToCreate = JSON.parse(JSON.stringify(cloneThis));

कोड:

// extends 'from' object with members from 'to'. If 'to' is null, a deep clone of 'from' is returned
function extend(from, to)
{
    if (from == null || typeof from != "object") return from;
    if (from.constructor != Object && from.constructor != Array) return from;
    if (from.constructor == Date || from.constructor == RegExp || from.constructor == Function ||
        from.constructor == String || from.constructor == Number || from.constructor == Boolean)
        return new from.constructor(from);

    to = to || new from.constructor();

    for (var name in from)
    {
        to[name] = typeof to[name] == "undefined" ? extend(from[name], null) : to[name];
    }

    return to;
}

परीक्षा:

var obj =
{
    date: new Date(),
    func: function(q) { return 1 + q; },
    num: 123,
    text: "asdasd",
    array: [1, "asd"],
    regex: new RegExp(/aaa/i),
    subobj:
    {
        num: 234,
        text: "asdsaD"
    }
}

var clone = extend(obj);

यह मेरा पसंदीदा समाधान है:

var obj = {};
return Object.keys(obj).length; //returns 0 if empty or an integer > 0 if non-empty




javascript object clone