javascript - सरण - जावास्क्रिप्ट सवाल




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

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

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


कोड की एक पंक्ति में जावास्क्रिप्ट ऑब्जेक्ट को क्लोन करने का एक शानदार तरीका

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

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

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

और पढो...

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

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

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

var destination = angular.copy(source);

या

angular.copy(source, destination);

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


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

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

मैं अपने सभी बच्चों और उनके बच्चों के साथ जावास्क्रिप्ट 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


एक विशेष रूप से सुरुचिपूर्ण समाधान उन वस्तुओं की गहरी प्रतियां बनाने के लिए 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

जावास्क्रिप्ट में किसी ऑब्जेक्ट के लिए ऐसा करने के लिए सरल या सीधा नहीं होगा। आप ऑब्जेक्ट के प्रोटोटाइप से गलती से गुणों को चुनने की समस्या में भाग लेंगे जो प्रोटोटाइप में छोड़ा जाना चाहिए और नए इंस्टेंस में कॉपी नहीं किया जाना चाहिए। उदाहरण के लिए, यदि आप Object.prototype एक clone विधि जोड़ रहे हैं, जैसा कि कुछ उत्तरों दर्शाते हैं, तो आपको उस विशेषता को स्पष्ट रूप से छोड़ना होगा। लेकिन क्या होगा यदि Object.prototype , या अन्य इंटरमीडिएट प्रोटोटाइप में जोड़े गए अन्य अतिरिक्त तरीके हैं, जिन्हें आप नहीं जानते हैं? उस स्थिति में, आप उन गुणों की प्रतिलिपि hasOwnProperty आपको नहीं करना चाहिए, इसलिए आपको hasOwnProperty विधि के साथ अप्रत्याशित, गैर-स्थानीय विशेषताओं का पता लगाना होगा।

गैर-गणना योग्य विशेषताओं के अतिरिक्त, जब आप छिपी हुई संपत्तियों की प्रतिलिपि बनाने की कोशिश करते हैं तो आपको एक कठिन समस्या का सामना करना पड़ेगा। उदाहरण के लिए, prototype एक समारोह की एक छिपी हुई संपत्ति है। साथ ही, किसी ऑब्जेक्ट के प्रोटोटाइप को __proto__ विशेषता के साथ संदर्भित किया __proto__ , जो भी छिपा हुआ है, और स्रोत ऑब्जेक्ट के गुणों पर पुनरावृत्ति के लिए / लूप द्वारा कॉपी नहीं किया जाएगा। मुझे लगता है कि __proto__ फ़ायरफ़ॉक्स के जावास्क्रिप्ट दुभाषिया के लिए विशिष्ट हो सकता है और यह अन्य ब्राउज़रों में कुछ अलग हो सकता है, लेकिन आपको तस्वीर मिलती है। सबकुछ गिनती नहीं है। यदि आप इसका नाम जानते हैं तो आप एक छिपी हुई विशेषता की प्रतिलिपि बना सकते हैं, लेकिन मुझे इसे स्वचालित रूप से खोजने के किसी भी तरीके से नहीं पता है।

एक सुरुचिपूर्ण समाधान की तलाश में एक और झगड़ा प्रोटोटाइप विरासत को सही ढंग से स्थापित करने की समस्या है। यदि आपका स्रोत ऑब्जेक्ट का प्रोटोटाइप Object , तो बस {} साथ एक नया सामान्य ऑब्जेक्ट बनाना काम करेगा, लेकिन यदि स्रोत का प्रोटोटाइप Object कुछ वंशज हैं, तो आप उस प्रोटोटाइप के अतिरिक्त सदस्यों को गायब होने जा रहे हैं जिन्हें आपने छोड़ा था hasOwnProperty फ़िल्टर, या जो प्रोटोटाइप में थे, लेकिन पहली जगह में गणना योग्य नहीं थे। प्रारंभिक प्रति ऑब्जेक्ट प्राप्त करने के लिए स्रोत ऑब्जेक्ट की constructor प्रॉपर्टी को कॉल करने के लिए एक समाधान हो सकता है और फिर विशेषताओं पर प्रतिलिपि बना सकता है, लेकिन तब भी आपको गैर-गणना योग्य गुण नहीं मिलेंगे। उदाहरण के लिए, एक Date वस्तु एक छिपी सदस्य के रूप में अपना डेटा संग्रहीत करती है:

function clone(obj) {
    if (null == obj || "object" != typeof obj) return obj;
    var copy = obj.constructor();
    for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return copy;
}

var d1 = new Date();

/* Executes function after 5 seconds. */
setTimeout(function(){
    var d2 = clone(d1);
    alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
}, 5000);

d1 लिए दिनांक स्ट्रिंग d1 2 के पीछे 5 सेकंड होगी। एक Date को दूसरे के समान बनाने का एक तरीका setTime विधि को कॉल करके है, लेकिन यह Date वर्ग के लिए विशिष्ट है। मुझे नहीं लगता कि इस समस्या का बुलेट प्रूफ सामान्य समाधान है, हालांकि मुझे गलत होने में खुशी होगी!

जब मुझे सामान्य गहरी प्रतिलिपि लागू करना पड़ा, तो मैंने यह मानकर समझौता किया कि मुझे केवल एक सादा Object , Array , Date , String , Number , या Boolean प्रतिलिपि बनाना होगा। पिछले 3 प्रकार अपरिवर्तनीय हैं, इसलिए मैं एक उथली प्रतिलिपि कर सकता हूं और इसे बदलने के बारे में चिंता नहीं कर सकता। मैंने आगे माना कि Object या Array में निहित कोई भी तत्व उस सूची में 6 साधारण प्रकारों में से एक होगा। इसे निम्नलिखित कोड के साथ पूरा किया जा सकता है:

function clone(obj) {
    var copy;

    // Handle the 3 simple types, and null or undefined
    if (null == obj || "object" != typeof obj) return obj;

    // Handle Date
    if (obj instanceof Date) {
        copy = new Date();
        copy.setTime(obj.getTime());
        return copy;
    }

    // Handle Array
    if (obj instanceof Array) {
        copy = [];
        for (var i = 0, len = obj.length; i < len; i++) {
            copy[i] = clone(obj[i]);
        }
        return copy;
    }

    // Handle Object
    if (obj instanceof Object) {
        copy = {};
        for (var attr in obj) {
            if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
        }
        return copy;
    }

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

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

// This would be cloneable:
var tree = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "right" : null,
    "data"  : 8
};

// This would kind-of work, but you would get 2 copies of the 
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a  due to infinite recursion:
var cyclicGraph = {
    "left"  : { "left" : null, "right" : null, "data" : 3 },
    "data"  : 8
};
cyclicGraph["right"] = cyclicGraph;

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


प्रति MDN :

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

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


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

y = _.clone(x);

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

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

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

पूरा क्लोन:

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


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

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

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

let objClone = { ...obj };

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


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

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



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

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

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


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

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

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

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

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 () डिफ़ॉल्ट रूप से गलत के लिए गणना करता है।


पुराने सवाल का नया जवाब! यदि आपको स्प्रेड सिंटेक्स के साथ ECMAScript 2016 (ES6) का उपयोग करने का आनंद है , तो यह आसान है।

keepMeTheSame = {first: "Me!", second: "You!"};
cloned = {...keepMeTheSame}

यह किसी ऑब्जेक्ट की उथली प्रतिलिपि के लिए एक साफ विधि प्रदान करता है। एक गहरी प्रतिलिपि बनाना, जिसका मतलब हर पुनरावर्ती घोंसला वाले ऑब्जेक्ट में प्रत्येक मूल्य की एक नई प्रतिलिपि बनाना है, ऊपर के भारी समाधानों की आवश्यकता है।

जावास्क्रिप्ट विकसित रहता है।


मैं बस Object.createइस पोस्ट में सभी समाधानों को जोड़ना चाहता था , यह नोडज के साथ वांछित तरीके से काम नहीं करता है।

फ़ायरफ़ॉक्स में परिणाम

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´

है

{test:"test"}

नोडज में यह है

{}

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

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





clone