Nodejs: किसी ऑब्जेक्ट को क्लोन कैसे करें


90

यदि मैं एक सरणी क्लोन करता हूं, तो मैं उपयोग करता हूं cloneArr = arr.slice()

मैं जानना चाहता हूं कि नोडज में किसी ऑब्जेक्ट को कैसे क्लोन किया जाए।

जवाबों:


175

उपयोगिताओं और कक्षाओं के लिए जहां प्रदर्शन की हर बूंद को निचोड़ने की आवश्यकता नहीं होती है, मैं अक्सर धोखा देता हूं और एक गहन प्रदर्शन करने के लिए सिर्फ JSON का उपयोग करता हूं:

function clone(a) {
   return JSON.parse(JSON.stringify(a));
}

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


2
@djechlin ज़रूर करता है। इसे आज़माएं: jsfiddle.net/katowulf/E5jC3 (नोड 0.10.11 के साथ परीक्षण किया गया) यह फ़ंक्शंस या प्रोटोटाइप डेटा को पुनर्गठित करने में सक्षम नहीं होने जा रहा है, लेकिन यह सिर्फ ठीक के आसपास मूल्यों को प्राप्त करता है।
काटो

11
यह तारीखों को स्ट्रिंग्स में बदल देगा
बैकसाइड

4
@ बेकस के साथ ही वस्तुओं और कार्यों।
काटो

2
@ काटो, परिपत्र संदर्भों का अर्थ यह होगा कि गहरी प्रतियां बनाने की कोई आवश्यकता नहीं है? वे दो असंबंधित चीजें हैं। NodeJS के लिए एक अच्छा क्लोन विधि लिखना निश्चित रूप से संभव है जो परिपत्र संदर्भों का समर्थन करता है और JSON से क्लोन का उपयोग करने से पीछे नहीं हटता है। github.com/pvorb/node-clone
सैमुअल नेफ

2
टिप्पणियों और विवरण में पहले से ही उल्लेख किया गया है। आप किसी फ़ंक्शन, ऑब्जेक्ट प्रोटोटाइप या अन्य चीजों को क्लोन नहीं कर सकते हैं जिन्हें आपको जेनेरिक क्लोन विधि के साथ करने की कोशिश नहीं करनी चाहिए। आपको उसके लिए एक से अधिक लाइन की कोड की आवश्यकता होगी, और संभवतः उस कबाड़ को क्लोन नहीं किया जाना चाहिए - अपनी कक्षा पर एक क्लोन विधि डालें जो जानता है कि इंटर्नल को कैसे संभालना है और क्या करना हैnewObj = obj.clone(args...);
काटो

34

उपर्युक्त किसी भी उत्तर में Object.assign का उल्लेख नहीं किया गया है।

let cloned = Object.assign({}, source);

यदि आप ES6 पर हैं, तो आप प्रसार ऑपरेटर का उपयोग कर सकते हैं:

let cloned = { ... source };

संदर्भ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign


28
ध्यान दें कि ये दोनों उथले क्लोन हैं और वस्तुओं पर प्रसार ऑपरेटर को नोड + 8s की आवश्यकता है।
jlh

1
जैसा कि @jlh ने उल्लेख किया है कि यह नेस्टेड वस्तुओं के लिए काम करने वाला नहीं है। आप इस विधि के गहरे क्लोन मुद्दों पर और अधिक पढ़ सकते हैं: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
शैंड

जैसा कि शैंड ने कहा, यह जवाब गलत है। गहरी क्लोनिंग के लिए, हमें अन्य विकल्पों का उपयोग करने की आवश्यकता है क्योंकि Object.assign () संपत्ति मूल्यों की प्रतिलिपि बनाता है। यदि स्रोत मान किसी ऑब्जेक्ट का संदर्भ है, तो यह केवल उस संदर्भ मान की प्रतिलिपि बनाता है।
ट्रॉय

1
यह क्लोन नहीं करता है, यह केवल मूल वस्तु का संदर्भ देता है, जिसका अर्थ है कि यदि आप कुछ बदलते हैं तो यह मास्टर के पास जाएगा
एडन वेल्च

@ एडनवेल मुझे नहीं लगता कि यह सही है। let a = {x:1}; let b = Object.assign({}, a); a.x = 2; a.y = 1; console.log(a, b);
मिगुएल पाइन्टो

20

अगर वहाँ "अपने खुद के रोल" नहीं करना चाहते हैं तो कुछ नोड मॉड्यूल हैं। यह एक अच्छा लग रहा है: https://www.npmjs.com/package/clone

ऐसा लगता है कि यह परिपत्र संदर्भ सहित सभी प्रकार के सामान को संभालता है। से GitHub पेज:

क्लोन मास्टर्स ऑब्जेक्ट्स, सरणियों, दिनांक ऑब्जेक्ट्स और RegEx ऑब्जेक्ट्स का क्लोनिंग करते हैं। सब कुछ पुनरावर्ती रूप से क्लोन किया जाता है, ताकि आप ऑब्जेक्ट में सरणियों में दिनांक क्लोन कर सकें, उदाहरण के लिए। [...] परिपत्र संदर्भ? हां!


10

यह एक सामान्य लेकिन उपयोगी क्लोन ऑपरेशन करना कठिन है क्योंकि जो पुनरावर्ती रूप से क्लोन किया जाना चाहिए और जो कॉपी किया जाना चाहिए वह इस बात पर निर्भर करता है कि विशिष्ट वस्तु को कैसे काम करना चाहिए।

जो कुछ उपयोगी हो सकता है वह है

function clone(x)
{
    if (x === null || x === undefined)
        return x;
    if (typeof x.clone === "function")
        return x.clone();
    if (x.constructor == Array)
    {
        var r = [];
        for (var i=0,n=x.length; i<n; i++)
            r.push(clone(x[i]));
        return r;
    }
    return x;
}

इस कोड में तर्क है

  • के मामले में nullया undefinedबस लौट ही (विशेष मामले की जरूरत है, क्योंकि यह एक त्रुटि है, तो एक को देखने के लिए प्रयास करने के लिए cloneविधि मौजूद है)
  • वस्तु एक cloneविधि है? तो उस का उपयोग करें
  • वस्तु एक सरणी है? फिर एक पुनरावर्ती क्लोनिंग ऑपरेशन करें
  • अन्यथा बस उसी मूल्य को वापस करें

इस क्लोन फ़ंक्शन को कस्टम क्लोन तरीकों को आसानी से लागू करने की अनुमति देनी चाहिए ... उदाहरण के लिए

function Point(x, y)
{
    this.x = x;
    this.y = y;

    ...
}

Point.prototype.clone = function()
{
    return new Point(this.x, this.y);
};



function Polygon(points, style)
{
    this.points = points;
    this.style = style;

    ...
}

Polygon.prototype.clone = function()
{
    return new Polygon(clone(this.points),
                       this.style);
};

जब वस्तु में आप जानते हैं कि एक विशिष्ट सरणी के लिए एक सही क्लोनिंग ऑपरेशन सिर्फ एक उथली प्रतिलिपि है तो आप values.slice()इसके बजाय कॉल कर सकते हैं clone(values)

उदाहरण के लिए उपरोक्त कोड में मुझे स्पष्ट रूप से आवश्यकता है कि बहुभुज वस्तु का एक क्लोनिंग अंक को क्लोन करेगा, लेकिन उसी शैली की वस्तु को साझा करेगा। अगर मैं इसके बजाय स्टाइल ऑब्जेक्ट को क्लोन करना चाहता हूं तो मैं बस पास कर सकता हूं clone(this.style)


1
+1 यह उल्लेख करने के लिए कि वस्तुओं को .cloneस्वयं विधि लागू करने की आवश्यकता है । क्लोनिंग ऑब्जेक्ट से निपटने का यह सबसे अच्छा तरीका है।
रेयानोस

3
if (x.clone)होना चाहिएif (typeof x.clone === 'function')
यानिक रोचॉन

@YanickRochon: धन्यवाद, निश्चित। क्षमा करें, किसी तरह मैंने इस टिप्पणी को पहले नहीं देखा ...
6502

9

क्लोनिंग ऑब्जेक्ट्स के लिए कोई मूल विधि नहीं है। अंडरस्कोर लागू करता है_.clone करता है जो एक उथले क्लोन है।

_.clone = function(obj) {
  return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
};

यह या तो इसे काट देता है या इसका विस्तार करता है।

यहां बताया गया है _.extend

// extend the obj (first parameter)
_.extend = function(obj) {
  // for each other parameter
  each(slice.call(arguments, 1), function(source) {
    // loop through all properties of the other objects
    for (var prop in source) {
      // if the property is not undefined then add it to the object.
      if (source[prop] !== void 0) obj[prop] = source[prop];
    }
  });
  // return the object (first parameter)
  return obj;
};

बस सभी आइटम्स के माध्यम से पुनरावृत्त करें और इसमें आइटमों के साथ एक नई वस्तु बनाएं।

यदि आप चाहते हैं तो आप अपने स्वयं के अनुभवहीन कार्यान्वयन को रोल आउट कर सकते हैं

function clone(o) {
  var ret = {};
  Object.keys(o).forEach(function (val) {
    ret[val] = o[val];
  });
  return ret;
}

गहरी क्लोनिंग से बचने के अच्छे कारण हैं क्योंकि क्लोजर को क्लोन नहीं किया जा सकता है।

मैंने व्यक्तिगत रूप से एक प्रश्न पूछा है deep cloning objects beforeऔर मैं जिस निष्कर्ष पर पहुंचा हूं वह यह है कि आप ऐसा नहीं करते हैं।

मेरी सिफारिश का उपयोग है underscoreऔर यह _.cloneउथले क्लोनों के लिए विधि है


9

उथली प्रतिलिपि के लिए, मैं कम पैटर्न (आमतौर पर एक मॉड्यूल या इस तरह) का उपयोग करना पसंद करता हूं, जैसे:

var newObject = Object.keys(original).reduce(function (obj, item) {
    obj[item] = original[item];
    return obj;
},{});

यहाँ विकल्पों के एक जोड़े के लिए एक jsperf है: http://jsperf.com/shallow-copying


सरल, सुरुचिपूर्ण, शानदार। मैं आपके अन्य SO योगदानों की प्रतीक्षा कर रहा हूं ^ _ ^
धन्यवाद

7

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

var extend = require("util")._extend;

var varToCopy = { test: 12345, nested: { val: 6789 } };

var copiedObject = extend({}, varToCopy);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 } }

किसी खाली वस्तु {} के साथ पहले पैरामीटर के उपयोग पर ध्यान दें - यह बताता है कि प्रतिलिपि की गई वस्तु (ओं) को एक नई वस्तु में कॉपी करने की आवश्यकता है। यदि आप पहले पैरामीटर के रूप में किसी मौजूदा ऑब्जेक्ट का उपयोग करते हैं, तो दूसरा (और बाद के सभी) पैरामीटर पहले पैरामीटर चर पर गहरे-मर्ज-कॉपी होंगे।

उपरोक्त उदाहरण चर का उपयोग करके, आप यह भी कर सकते हैं:

var anotherMergeVar = { foo: "bar" };

extend(copiedObject, { anotherParam: 'value' }, anotherMergeVar);

console.log(copiedObject);

// outputs:
// { test: 12345, nested: { val: 6789 }, anotherParam: 'value', foo: 'bar' }

बहुत उपयोगी उपयोगिता, विशेष रूप से जहां मुझे AngularJS और jQuery में विस्तार करने के लिए उपयोग किया जाता है।

मनाइए कि यह किसी और के लिए सहायक हो; ऑब्जेक्ट संदर्भ ओवरराइट एक दुख है, और यह हर बार इसे हल करता है!


1
_Extend का उपयोग करना अब मूल्यह्रास हो गया है। इसके बजाय Object.assign () का उपयोग करें: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
MacroMan

7

आप चाहें तो लॉश का भी इस्तेमाल कर सकते हैं । इसमें एक क्लोन और क्लोनडिप विधियां हैं।

var _= require('lodash');

var objects = [{ 'a': 1 }, { 'b': 2 }];

var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);
// => true

var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);

1

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

var clonedObject = Object.create(originalObject);

बस याद रखें कि यह एक पूर्ण क्लोन नहीं है - बेहतर या बदतर के लिए।

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

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


3
यह बहुत ही खतरनाक है और एक क्लोन के बिल्कुल विपरीत है। var a = {foo: "bar"}, b = Object.create(a); a.foo = "broken"; console.log(b.foo); // "broken";
धन्यवाद

@naomik: b.foo = "working"; console.log(a.foo); // still "broken";निश्चित रूप से इस बात से अवगत होना चाहिए कि मूल वस्तु में परिवर्तन "क्लोन" में परिलक्षित होगा और "क्लोन" में होने वाले परिवर्तन मूल वस्तु में परिलक्षित नहीं होंगे - लेकिन मैं इसे खतरनाक नहीं कहूंगा। - यह सब इस बात पर निर्भर करता है कि आप अपने क्लोन के साथ क्या करना चाहते हैं
वोक्सपेली

@naomik: मैं JS के लिए काफी नया हूँ, इसलिए मैं कुछ पूर्वापेक्षाएँ चाहूँगा। Olli-k द्वारा प्रस्तावित उथले क्लोन और जो आपको पसंद आया लगता है (IMHO, लेकिन मैं गलत हो सकता है) voxpelli द्वारा प्रस्तावित समाधान की तुलना में समान सीमाएं हैं। मूल और उथले पास भी समान "आइटम" साझा करेंगे, मूल में किसी आइटम को अपडेट करने से भी उथले क्लोन पर प्रभाव पड़ेगा। या?
बेमोरिन

@bmornin, यदि आप Olli K की तकनीक का उपयोग करते हैं, तो मूल वस्तु को संशोधित करने से नई वस्तु में बदलाव नहीं होगा ।
शुक्रिया

1
@VoxPelli एक "क्लोन" का पूरा उद्देश्य मूल वस्तु से अलग परिवर्तन करने के लिए है, इसलिए इस पद्धति है ज्यादा खतरनाक।
डग

1

मैंने पूरी गहरी कॉपी लागू की। मेरा मानना ​​है कि जेनेरिक क्लोन विधि के लिए इसकी सबसे अच्छी पसंद है, लेकिन यह चक्रीय संदर्भों को नहीं संभालता है।

उपयोग उदाहरण:

parent = {'prop_chain':3}
obj = Object.create(parent)
obj.a=0; obj.b=1; obj.c=2;

obj2 = copy(obj)

console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3
console.log(obj2, obj2.prop_chain)
// '{'a':0, 'b':1, 'c':2} 3

parent.prop_chain=4
obj2.a = 15

console.log(obj, obj.prop_chain)
// '{'a':0, 'b':1, 'c':2} 4
console.log(obj2, obj2.prop_chain)
// '{'a':15, 'b':1, 'c':2} 4

कोड ही:

यह कोड वस्तुओं को उनके प्रोटोटाइप के साथ कॉपी करता है, यह फ़ंक्शन को भी कॉपी करता है (किसी के लिए उपयोगी हो सकता है)।

function copy(obj) {
  // (F.prototype will hold the object prototype chain)
  function F() {}
  var newObj;

  if(typeof obj.clone === 'function')
    return obj.clone()

  // To copy something that is not an object, just return it:
  if(typeof obj !== 'object' && typeof obj !== 'function' || obj == null)
    return obj;

  if(typeof obj === 'object') {    
    // Copy the prototype:
    newObj = {}
    var proto = Object.getPrototypeOf(obj)
    Object.setPrototypeOf(newObj, proto)
  } else {
    // If the object is a function the function evaluate it:
    var aux
    newObj = eval('aux='+obj.toString())
    // And copy the prototype:
    newObj.prototype = obj.prototype
  }

  // Copy the object normal properties with a deep copy:
  for(var i in obj) {
    if(obj.hasOwnProperty(i)) {
      if(typeof obj[i] !== 'object')
        newObj[i] = obj[i]
      else
        newObj[i] = copy(obj[i])
    }
  }

  return newObj;
}

इस प्रति के साथ मुझे मूल और कॉपी किए गए एक के बीच कोई अंतर नहीं मिल सकता है, सिवाय इसके कि अगर मूल इसके निर्माण पर बंद हुआ, तो मुझे लगता है कि यह एक अच्छा कार्यान्वयन है।

मुझे उम्मीद है यह मदद करेगा


1

सरणी के लिए, कोई भी उपयोग कर सकता है

var arr = [1,2,3]; 
var arr_2 = arr ; 

print ( arr_2 ); 

आगमन = arr.slice (0);

print ( arr ); 

arr[1]=9999; 

print ( arr_2 ); 

1

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

npm इंस्टाल करें

const ld = require('lodash')
const objectToCopy = {name: "john", age: 24}
const clonedObject = ld.cloneDeep(objectToCopy)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.