javascript - मैं जावास्क्रिप्ट ऑब्जेक्ट को सही ढंग से क्लोन कैसे करूं?




clone (25)

मेरे पास एक वस्तु है, x । मैं इसे ऑब्जेक्ट y रूप में कॉपी करना चाहता हूं, जैसे y परिवर्तन x संशोधित नहीं करते हैं। मुझे एहसास हुआ कि अंतर्निहित जावास्क्रिप्ट ऑब्जेक्ट्स से व्युत्पन्न वस्तुओं को कॉपी करने के परिणामस्वरूप अतिरिक्त, अवांछित गुण होंगे। यह कोई समस्या नहीं है, क्योंकि मैं अपनी खुद की, शाब्दिक-निर्मित वस्तुओं में से एक की प्रतिलिपि बना रहा हूं।

मैं जावास्क्रिप्ट ऑब्जेक्ट को सही ढंग से क्लोन कैसे करूं?


Answers

let clone = Object.assign( Object.create( Object.getPrototypeOf(obj)), obj)

ईएस 6 समाधान यदि आप (उथला) क्लोन को एक क्लास इंस्टेंस करना चाहते हैं, न सिर्फ एक संपत्ति ऑब्जेक्ट।


Object.assign 6 में Object.assign विधि है, जो सभी वस्तुओं के मूल्यों को एक ऑब्जेक्ट से दूसरे ऑब्जेक्ट में कॉपी करती है। उदाहरण के लिए:

var x = {myProp: "value"};
var y = Object.assign({}, x); 

लेकिन ध्यान रखें कि नेस्टेड ऑब्जेक्ट्स को अभी भी संदर्भ के रूप में कॉपी किया गया है।


यदि आप एक उथले प्रतिलिपि के साथ ठीक हैं, तो underscore.js लाइब्रेरी में clone विधि है।

y = _.clone(x);

या आप इसे विस्तारित कर सकते हैं

copiedObject = _.extend({},originalObject);

इंटरनेट पर अधिकतर समाधानों के साथ कई मुद्दे हैं। तो मैंने एक फॉलो-अप करने का फैसला किया, जिसमें शामिल है, स्वीकृत उत्तर क्यों स्वीकार नहीं किया जाना चाहिए।

शुरुआती स्थिति

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

इसके बाद, हम 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 मिल जाएगा 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 भी संभालता 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"
    }
}

... और आप देखते हैं, यह अंदर घोंसला संरचना के साथ काम नहीं किया।

मूल समाधान के लिए polyfill

पुराने ब्राउज़र में Object.create लिए Object.create सिर्फ आईई 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

आवश्यकताओं का मिलान किया जाता है, लेकिन अभी भी कुछ छोटे मुद्दे हैं, जिनमें nested और circ Object के instance को बदलना शामिल है।

पत्ते साझा करने वाले पेड़ों की संरचना की प्रतिलिपि नहीं बनाई जाएगी, वे दो स्वतंत्र पत्तियां बन जाएंगी:

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

निष्कर्ष

रिकर्सन और कैश का उपयोग करने वाला अंतिम समाधान सबसे अच्छा नहीं हो सकता है, लेकिन यह ऑब्जेक्ट की वास्तविक गहरी प्रतिलिपि है। यह सरल properties , circular structures और nested object संभालता है, लेकिन क्लोनिंग के दौरान यह उनके उदाहरण को गड़बड़ कर देगा।

jsfiddle


प्रति MDN :

  • यदि आप उथली प्रतिलिपि चाहते हैं, तो Object.assign({}, a)
  • "गहरी" प्रतिलिपि के लिए, JSON.parse(JSON.stringify(a))

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


AngularJS का उपयोग करने वालों के लिए, इस पुस्तकालय में वस्तुओं को क्लोनिंग या विस्तार करने के लिए भी सीधी विधि है।

var destination = angular.copy(source);

या

angular.copy(source, destination);

Angular.copy documentation में अधिक ...


लोडाश का उपयोग करना:

var y = _.clone(x, true);

संदर्भ के बिना किसी ऑब्जेक्ट की प्रतिलिपि बनाने के लिए आप बस एक स्प्रेड प्रॉपर्टी का उपयोग कर सकते हैं । लेकिन सावधान रहें (टिप्पणियां देखें), 'प्रतिलिपि' केवल निम्नतम वस्तु / सरणी स्तर पर है। नेस्टेड गुण अभी भी संदर्भ हैं!

पूरा क्लोन:

let x = {a: 'value1'}
let x2 = {...x}

// => mutate without references:

x2.a = 'value2'
console.log(x.a)    // => 'value1'

दूसरे स्तर पर संदर्भ के साथ क्लोन करें:

const y = {a: {b: 'value3'}}
const y2 = {...y}

// => nested object is still a references:

y2.a.b = 'value4'
console.log(y.a.b)    // => 'value4'

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

http://ramdajs.com/docs/#clone


JQuery के साथ, आप extend साथ उथले प्रतिलिपि बना सकते extend :

var copiedObject = jQuery.extend({}, originalObject)

copiedObject में बाद में परिवर्तन मूल ऑब्जेक्ट को प्रभावित नहीं करेंगे, और इसके विपरीत।

या एक गहरी प्रतिलिपि बनाने के लिए:

var copiedObject = jQuery.extend(true, {}, originalObject)

कई जवाब हैं, लेकिन कोई भी जो Object.create 5 से Object.create का उल्लेख नहीं करता है, जो Object.create से आपको एक सटीक प्रति नहीं देता है, लेकिन स्रोत को नई वस्तु के प्रोटोटाइप के रूप में सेट करता है।

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

  1. जहां ऐसी विरासत उपयोगी है (दुह!)
  2. जहां स्रोत ऑब्जेक्ट को संशोधित नहीं किया जाएगा, इस प्रकार 2 ऑब्जेक्ट्स के बीच संबंध को एक गैर समस्या बनाते हैं।

उदाहरण:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property

मैं इस समाधान को श्रेष्ठ क्यों मानता हूं? यह मूल है, इस प्रकार कोई लूपिंग नहीं, कोई रिकर्सन नहीं है। हालांकि, पुराने ब्राउज़र को पॉलीफिल की आवश्यकता होगी।


ईसीएमएस्क्रिप्ट 2018 में

let objClone = { ...obj };

ध्यान रखें कि नेस्टेड ऑब्जेक्ट्स को अभी भी एक संदर्भ के रूप में कॉपी किया गया है।


एलेवी का जवाब लगभग पूरा हो गया है, यहां मेरा छोटा योगदान है: रिकर्सिव संदर्भों को संभालने का एक तरीका है , इस लाइन को देखें

if(this[attr]==this) copy[attr] = copy;

यदि ऑब्जेक्ट XML DOM तत्व है, तो हमें इसके बजाय क्लोन नोड का उपयोग करना होगा

if(this.cloneNode) return this.cloneNode(true);

एलेवी के संपूर्ण अध्ययन और कैल्विन के प्रोटोटाइप दृष्टिकोण से प्रेरित, मैं इस समाधान की पेशकश करता हूं:

Object.prototype.clone = function() {
  if(this.cloneNode) return this.cloneNode(true);
  var copy = this instanceof Array ? [] : {};
  for(var attr in this) {
    if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
      copy[attr] = this[attr];
    else if(this[attr]==this) copy[attr] = copy;
    else copy[attr] = this[attr].clone();
  }
  return copy;
}

Date.prototype.clone = function() {
  var copy = new Date();
  copy.setTime(this.getTime());
  return copy;
}

Number.prototype.clone = 
Boolean.prototype.clone =
String.prototype.clone = function() {
  return this;
}

जवाब में एंडी बर्क के नोट भी देखें।


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

var cloneOfA = JSON.parse(JSON.stringify(a));

यह ऑब्जेक्ट्स, सरणी, तार, बुलियन और संख्या वाले सभी प्रकार की वस्तुओं के लिए काम करता है।

ब्राउज़र के संरचित क्लोन एल्गोरिदम के बारे में यह लेख भी देखें, जिसका प्रयोग किसी कार्यकर्ता से संदेशों को पोस्ट करते समय किया जाता है। इसमें गहरे क्लोनिंग के लिए एक फ़ंक्शन भी शामिल है।


ईएस -6 में आप ऑब्जेक्ट.साइन (...) का उपयोग कर सकते हैं। उदाहरण के लिए:

let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);

एक अच्छा संदर्भ यहां है: https://googlechrome.github.io/samples/object-assign-es6/


ठीक है, कल्पना करें कि आपके पास यह ऑब्जेक्ट नीचे है और आप इसे क्लोन करना चाहते हैं:

let obj = {a:1, b:2, c:3}; //ES6

या

var obj = {a:1, b:2, c:3}; //ES5

जवाब में मुख्य रूप से depeneds जिस पर है ECMAScript आप उपयोग कर, में ES6+, आप बस का उपयोग कर सकते Object.assignक्लोन करने के लिए:

let cloned = Object.assign({}, obj); //new {a:1, b:2, c:3};

या इस तरह फैल ऑपरेटर का उपयोग कर:

let cloned = {...obj}; //new {a:1, b:2, c:3};

लेकिन यदि आप इसका उपयोग कर रहे हैं ES5, तो आप कुछ तरीकों का उपयोग कर सकते हैं, लेकिन JSON.stringify, सुनिश्चित करें कि आप कॉपी करने के लिए डेटा के एक बड़े हिस्से के लिए उपयोग नहीं कर रहे हैं, लेकिन यह कई मामलों में एक लाइन आसान तरीका हो सकता है, ऐसा कुछ:

let cloned = JSON.parse(JSON.stringify(obj)); 
//new {a:1, b:2, c:3};, can be handy, but avoid using on big chunk of data over and over

एक विशेष रूप से सुरुचिपूर्ण समाधान उन वस्तुओं की गहरी प्रतियां बनाने के लिए JSON एन्कोडिंग का उपयोग करना है जिनके पास सदस्य विधियां नहीं हैं। पद्धति JSON को आपके लक्षित ऑब्जेक्ट को एन्कोड करना है, फिर इसे डीकोड करके, आपको वह कॉपी मिलती है जिसे आप ढूंढ रहे हैं। आप जितनी बार चाहें उतनी प्रतियां बनाना चाहते हैं जितनी बार आप डीकोड कर सकते हैं।

बेशक, कार्य JSON में नहीं हैं, इसलिए यह केवल सदस्य विधियों के बिना वस्तुओं के लिए काम करता है।

यह पद्धति मेरे उपयोग के मामले के लिए बिल्कुल सही थी, क्योंकि मैं एक कुंजी-मूल्य स्टोर में JSON ब्लॉब्स संग्रहीत कर रहा हूं, और जब उन्हें जावास्क्रिप्ट एपीआई में ऑब्जेक्ट्स के रूप में उजागर किया जाता है, तो प्रत्येक ऑब्जेक्ट में वास्तव में ऑब्जेक्ट की मूल स्थिति की एक प्रति होती है ताकि हम कॉलर ने उजागर वस्तु को उत्परिवर्तित करने के बाद डेल्टा की गणना कर सकते हैं।

var object1 = {key:"value"};
var object2 = object1;

object2 = JSON.stringify(object1);
object2 = JSON.parse(object2);

object2.key = "a change";
console.log(object1);// returns value

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

function clone(obj){
    var clonedObjectsArray = [];
    var originalObjectsArray = []; //used to remove the unique ids when finished
    var next_objid = 0;

    function objectId(obj) {
        if (obj == null) return null;
        if (obj.__obj_id == undefined){
            obj.__obj_id = next_objid++;
            originalObjectsArray[obj.__obj_id] = obj;
        }
        return obj.__obj_id;
    }

    function cloneRecursive(obj) {
        if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") 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; i < obj.length; ++i) {
                copy[i] = cloneRecursive(obj[i]);
            }
            return copy;
        }

        // Handle Object
        if (obj instanceof Object) {
            if (clonedObjectsArray[objectId(obj)] != undefined)
                return clonedObjectsArray[objectId(obj)];

            var copy;
            if (obj instanceof Function)//Handle Function
                copy = function(){return obj.apply(this, arguments);};
            else
                copy = {};

            clonedObjectsArray[objectId(obj)] = copy;

            for (var attr in obj)
                if (attr != "__obj_id" && obj.hasOwnProperty(attr))
                    copy[attr] = cloneRecursive(obj[attr]);                 

            return copy;
        }       


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



    //remove the unique ids
    for (var i = 0; i < originalObjectsArray.length; i++)
    {
        delete originalObjectsArray[i].__obj_id;
    };

    return cloneObj;
}

कुछ त्वरित परीक्षण

var auxobj = {
    prop1 : "prop1 aux val", 
    prop2 : ["prop2 item1", "prop2 item2"]
    };

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
    this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));


यहां एक फ़ंक्शन है जिसका आप उपयोग कर सकते हैं।

function clone(obj) {
    if(obj == null || typeof(obj) != 'object')
        return obj;    
    var temp = new obj.constructor(); 
    for(var key in obj)
        temp[key] = clone(obj[key]);    
    return temp;
}

चूंकि mindeavor ने कहा कि क्लोन करने के लिए ऑब्जेक्ट एक 'शाब्दिक-निर्मित' ऑब्जेक्ट है, एक ऑब्जेक्ट ऑब्जेक्ट के उदाहरण को क्लोन करने के बजाय ऑब्जेक्ट को कई बार उत्पन्न करना हो सकता है :

function createMyObject()
{
    var myObject =
    {
        ...
    };
    return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();

मैंने अपना खुद का कार्यान्वयन लिखा है। सुनिश्चित नहीं है कि यह एक बेहतर समाधान के रूप में गिना जाता है:

/*
    a function for deep cloning objects that contains other nested objects and circular structures.
    objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
                                    index (z)
                                         |
                                         |
                                         |
                                         |
                                         |
                                         |                      depth (x)
                                         |_ _ _ _ _ _ _ _ _ _ _ _
                                        /_/_/_/_/_/_/_/_/_/
                                       /_/_/_/_/_/_/_/_/_/
                                      /_/_/_/_/_/_/...../
                                     /................./
                                    /.....            /
                                   /                 /
                                  /------------------
            object length (y)    /
*/

कार्यान्वयन निम्नलिखित है:

function deepClone(obj) {
    var depth = -1;
    var arr = [];
    return clone(obj, arr, depth);
}

/**
 *
 * @param obj source object
 * @param arr 3D array to store the references to objects
 * @param depth depth of the current object relative to the passed 'obj'
 * @returns {*}
 */
function clone(obj, arr, depth){
    if (typeof obj !== "object") {
        return obj;
    }

    var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'

    var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
    if(result instanceof Array){
        result.length = length;
    }

    depth++; // depth is increased because we entered an object here

    arr[depth] = []; // this is the x-axis, each index here is the depth
    arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
    // start the depth at current and go down, cyclic structures won't form on depths more than the current one
    for(var x = depth; x >= 0; x--){
        // loop only if the array at this depth and length already have elements
        if(arr[x][length]){
            for(var index = 0; index < arr[x][length].length; index++){
                if(obj === arr[x][length][index]){
                    return obj;
                }
            }
        }
    }

    arr[depth][length].push(obj); // store the object in the array at the current depth and length
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
    }

    return result;
}

डब्ल्यू 3 सी के "संरचित डेटा के सुरक्षित उत्तीर्ण" एल्गोरिदम के लिए http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#safe-passing-of-structured-data संरचित- डेटा से परामर्श लें , जिसे कार्यान्वित किया जाना है वेब श्रमिकों जैसे डेटा पास करने के लिए ब्राउज़र द्वारा। हालांकि, इसमें कुछ सीमाएं हैं, जिसमें यह कार्य को संभाल नहीं करता है। अधिक जानकारी के लिए https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm देखें , जिसमें जेएस में एक वैकल्पिक एल्गोरिदम शामिल है जो आपको वहां से भाग लेता है।


जनवरी टूरोर्न का उत्तर बहुत करीब है, और संगतता के मुद्दों के कारण ब्राउज़र में उपयोग करना सबसे अच्छा हो सकता है, लेकिन यह संभावित रूप से कुछ अजीब गणना मुद्दों का कारण बन जाएगा। उदाहरण के लिए, निष्पादन:

for ( var i in someArray ) { ... }

सरणी के तत्वों के माध्यम से पुन: प्रयास करने के बाद क्लोन () विधि को असाइन करेगा। यहां एक अनुकूलन है जो गणना से बचाता है और node.js के साथ काम करता है:

Object.defineProperty( Object.prototype, "clone", {
    value: function() {
        if ( this.cloneNode )
        {
            return this.cloneNode( true );
        }

        var copy = this instanceof Array ? [] : {};
        for( var attr in this )
        {
            if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
            {
                copy[ attr ] = this[ attr ];
            }
            else if ( this[ attr ] == this )
            {
                copy[ attr ] = copy;
            }
            else
            {
                copy[ attr ] = this[ attr ].clone();
            }
        }
        return copy;
    }
});

Object.defineProperty( Date.prototype, "clone", {
    value: function() {
        var copy = new Date();
        copy.setTime( this.getTime() );
        return copy;
    }
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );

यह क्लोन () विधि को गणना करने से बचाता है क्योंकि defineProperty () डिफ़ॉल्ट रूप से गलत के लिए गणना करता है।


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;
};

यहाँ एक समय देरी पुनर्निर्देशन है। आप जो भी चाहते हैं उसके लिए विलंब समय निर्धारित कर सकते हैं:

<!doctype html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Your Document Title</title>
    <script type="text/javascript">
        function delayer(delay) {
            onLoad = setTimeout('window.location.href = "http://www.google.com/"', delay);
        }
    </script>
</head>

<body>
    <script>
        delayer(8000)
    </script>
    <div>You will be redirected in 8 seconds!</div>
</body>

</html>




javascript clone