एक वस्तु को Node.js में क्लोन करना


203

नोड.जेएस में किसी वस्तु को क्लोन करने का सबसे अच्छा तरीका क्या है

उदाहरण के लिए मैं उस स्थिति से बचना चाहता हूँ जहाँ:

var obj1 = {x: 5, y:5};
var obj2 = obj1;
obj2.x = 6;
console.log(obj1.x); // logs 6

ऑब्जेक्ट में विशेषताओं के रूप में अच्छी तरह से जटिल प्रकार हो सकते हैं, इसलिए एक सरल (obj1 में var x) हल नहीं होगा। क्या मुझे स्वयं एक पुनरावर्ती क्लोन लिखने की आवश्यकता है या क्या इसमें कुछ ऐसा बनाया गया है जिसे मैं नहीं देख रहा हूं?


23
1. npm install underscore2. var _ = require('underscore')3. 3 _.clone(objToClone).;
सलमान वॉन अब्बास

4
ध्यान दें कि @ @ SalmanPK के ऊपर टिप्पणी में, यह एक उथला क्लोन है। इसलिए यह स्लिप्टी के उदाहरण के लिए काम करेगा, लेकिन अगर नेस्टेड एरेज़ या ऑब्जेक्ट हैं, तो वे संदर्भ होंगे। : /
जेसी

1
मुझे यह लेख बहुत उपयोगी लगा: heyjavascript.com/4-creative-ways-to-clone-objects
जॉर्डन हडसन

3
@ जोर्डन हडसन - दूसरे उदाहरण में JSON का बहुत अच्छा उपयोग। var newObj = JSON.parse (JSON.stringify (oldObj)); // अब newObj एक क्लोन है। केवल समस्या यह है कि पुनरावर्ती संदर्भ पर स्ट्रिंग काम नहीं करेगी, इसलिए सावधान रहने की आवश्यकता है।
काफिर इरेज़ जूल

जवाबों:


298

संभावना १

कम तामझाम गहरी प्रति:

var obj2 = JSON.parse(JSON.stringify(obj1));

संभावना 2 (पदावनत)

ध्यान दें: इस समाधान को अब Node.js के प्रलेखन में पदावनत के रूप में चिह्नित किया गया है :

आंतरिक Node.js मॉड्यूल के बाहर उपयोग करने के लिए कभी भी use._extend () विधि का उपयोग नहीं किया गया था। समुदाय ने वैसे भी पाया और इसका इस्तेमाल किया।

यह पदावनत है और इसका उपयोग नए कोड में नहीं किया जाना चाहिए। जावास्क्रिप्ट बहुत समान अंतर्निहित कार्यक्षमता के साथ Object.assign () के माध्यम से आता है।

मूल उत्तर :

उथली प्रतिलिपि के लिए, नोड के अंतर्निहित util._extend()फ़ंक्शन का उपयोग करें ।

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

var obj1 = {x: 5, y:5};
var obj2 = extend({}, obj1);
obj2.x = 6;
console.log(obj1.x); // still logs 5

नोड के _extendकार्य का स्रोत कोड यहाँ है: https://github.com/joyent/node/blob/master/lib/util.js

exports._extend = function(origin, add) {
  // Don't do anything if add isn't an object
  if (!add || typeof add !== 'object') return origin;

  var keys = Object.keys(add);
  var i = keys.length;
  while (i--) {
    origin[keys[i]] = add[keys[i]];
  }
  return origin;
};

5
प्रश्न विशेष रूप से एक पुनरावर्ती क्लोन के लिए कहा जाता है। यह एक उथला क्लोन है।
बेंजामिन एटकिन

28
क्या यह _*माना जाने वाला नाम नहीं है कि यह एक निजी पद्धति है और इस पर भरोसा नहीं किया जाना चाहिए?
शराबी

7
किसी भी आकार की प्रत्येक जावास्क्रिप्ट परियोजना में विस्तार () का एक या अधिक कार्यान्वयन होता है, और नोड कोई अपवाद नहीं है। Node.js कोर इस फ़ंक्शन का व्यापक उपयोग करता है। इसहाक को उद्धृत करने के लिए, "यह जल्द ही किसी भी समय कहीं भी नहीं जा रहा है।"
जिम्बो

2
मेरे लिए पूरी तरह से काम किया। ऑब्जेक्ट प्रोटोटाइप इमो के साथ खिलवाड़ करने से बहुत बेहतर है
माइकल डौसमैन

12
यह गलत जवाब है। नोड के दस्तावेज़ीकरण के अनुसार: nodejs.org/api/util.html#util_util_extend_obj इस util._extend()पद्धति का उपयोग आंतरिक Node.js मॉड्यूल के बाहर कभी नहीं किया गया था। समुदाय ने वैसे भी पाया और इसका इस्तेमाल किया। यह पदावनत है और इसका उपयोग नए कोड में नहीं किया जाना चाहिए। जावास्क्रिप्ट बहुत समान अंतर्निहित कार्यक्षमता के साथ आता हैObject.assign().
जॉर्डन

264

मुझे आश्चर्य Object.assignहै कि उल्लेख नहीं किया गया है।

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

यदि उपलब्ध हो (जैसे कोलाहल), तो आप ऑब्जेक्ट स्प्रेड ऑपरेटर का उपयोग कर सकते हैं :

let cloned = { ... source };

1
आपने मेरा दिन बचाया! धन्यवाद
wzr1337

2
तीसरे पक्ष के पुस्तकालय को आयात करने या अपूर्ण JSON वर्कअराउंड का उपयोग करने की तुलना में यह बहुत बेहतर समाधान है। धन्यवाद!
नील एस

75
यह एक उथली प्रतिलिपि है
जॉर्डन डेविडसन

14
गहरी क्लोन के लिए चेतावनी, गहरी क्लोन के लिए अभी भी अन्य विकल्पों का उपयोग करने की आवश्यकता है। developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
gsalgadotoledo

1
क्या मैं वस्तु प्रसार ऑपरेटर बता सकता हूँ से एक ES6 बात नहीं है, बल्कि एक मंच 3 प्रस्ताव है। जिसका मतलब है कि आप इसे बेबल के साथ उपयोग कर सकते हैं, लेकिन इसके बिना जो मुझे समझ में नहीं आता है। github.com/tc39/…
macdja38

24
Object.defineProperty(Object.prototype, "extend", {
    enumerable: false,
    value: function(from) {
        var props = Object.getOwnPropertyNames(from);
        var dest = this;
        props.forEach(function(name) {
            if (name in dest) {
                var destination = Object.getOwnPropertyDescriptor(from, name);
                Object.defineProperty(dest, name, destination);
            }
        });
        return this;
    }
});

यह एक विस्तार विधि को परिभाषित करेगा जिसका आप उपयोग कर सकते हैं। इस लेख से कोड आता है।


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

3
क्या यह वास्तव में काम करता है? "अगर (भाग्य में नाम)" - केवल संपत्ति को बदल देगा यदि यह पहले से ही भाग्य में मौजूद है। इसे नकारा जाना चाहिए।
मेमोरियल

8
क्या ऑब्जेक्ट को संशोधित नहीं किया जा रहा है। प्रोटोटाइप को शब्दशः माना जाता है? इसके अलावा लेख लिंक टूट गया है।
डेनियल शेफ़र

बस लेख लिंक की कोशिश की और यह मेरे लिए काम करता है। शायद यह एक नेटवर्क ब्लिप था जब आपने इसे आज़माया था।
माइकल डिलन

कई टिप्पणियों के आधार पर, मैंने एक ऐसे संस्करण को शामिल करने के लिए उत्तर को अपडेट किया है जो ऑब्जेक्ट के प्रोटोटाइप में नहीं जोड़ता है।
शमसिस भट्टाचार्य

20
var obj2 = JSON.parse(JSON.stringify(obj1));

2
इस मौजूदा उत्तर में पहले ही यह सुझाव दिया गया था कि कोई भी बिंदु इसे दोहराए नहीं।
शैडो विजार्ड ईयर फॉर यू

@ शडवॉइडर ये अलग तरीके हैं। यह केवल एक प्रकार से जोंस और बैक टू ऑब्जेक्ट में परिवर्तित हो जाता है, जबकि जुड़ा हुआ उत्तर Object.keys()ऑब्जेक्ट के माध्यम से पुनरावृति करने के लिए उपयोग करता है
mente

यह उत्तर गलत है। JSON.stringify डेट ऑब्जेक्ट लेता है और इसे स्ट्रिंग में घटाता है, और फिर पार्स करने के बाद इसे एक स्ट्रिंग के रूप में छोड़ता है, इसलिए यह आपकी ऑब्जेक्ट की स्थिति को उत्परिवर्तित करता है जो आपको तारीखों के मामले में शुरू में एक अलग ऑब्जेक्ट के साथ छोड़ देता है।
twboc

13

आप JQuery से विस्तार फ़ंक्शन का उपयोग कर सकते हैं:

var newClone= jQuery.extend({}, oldObject);  
var deepClone = jQuery.extend(true, {}, oldObject); 

एक Node.js प्लगइन भी है:

https://github.com/shimondoodkin/nodejs-clone-extend

JQuery या प्लगइन के बिना इसे करने के लिए इसे यहाँ पढ़ें:

http://my.opera.com/GreyWyvern/blog/show.dml/1725165


Node.js प्लगइन एकदम सही है। धन्यवाद!
जस्टिन

बहुत बढ़िया जवाब। मुझे छोटे उपयोगी मॉड्यूल पसंद हैं।
चेव


8

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

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

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


7

यह कोड कार्य कारण भी है। Object.create () विधि निर्दिष्ट प्रोटोटाइप ऑब्जेक्ट और गुणों के साथ एक नई वस्तु बनाता है।

var obj1 = {x:5, y:5};

var obj2 = Object.create(obj1);

obj2.x; //5
obj2.x = 6;
obj2.x; //6

obj1.x; //5

4
यह एक उथली प्रति है
रैडगैस्ट द ब्राउन

6

NodeJS में किसी ऑब्जेक्ट को क्लोन करने का सरल और सबसे तेज़ तरीका Object.keys (obj) विधि का उपयोग करना है

var a = {"a": "a11", "b": "avc"};
var b;

for(var keys = Object.keys(a), l = keys.length; l; --l)
{
   b[ keys[l-1] ] = a[ keys[l-1] ];
}
b.a = 0;

console.log("a: " + JSON.stringify(a)); // LOG: a: {"a":"a11","b":"avc"} 
console.log("b: " + JSON.stringify(b)); // LOG: b: {"a":0,"b":"avc"}

विधि Object.keys के लिए जावास्क्रिप्ट 1.8.5 की आवश्यकता होती है; इस विधि का समर्थन करता है

लेकिन निश्चित रूप से नेस्टेड वस्तुओं के लिए पुनरावर्ती कवक को लागू करने की आवश्यकता है


अन्य समाधान देशी JSON (जावास्क्रिप्ट 1.7 में लागू) का उपयोग करना है, लेकिन यह पिछले एक की तुलना में बहुत धीमा (~ 10 गुना धीमा) है

var a = {"a": i, "b": i*i};
var b = JSON.parse(JSON.stringify(a));
b.a = 0;

5

गितुब पर एक परियोजना भी है जिसका लक्ष्य अधिक प्रत्यक्ष बंदरगाह होना है jQuery.extend():

https://github.com/dreamerslab/node.extend

एक उदाहरण, jQuery डॉक्स से संशोधित :

var extend = require('node.extend');

var object1 = {
    apple: 0,
    banana: {
        weight: 52,
        price: 100
    },
    cherry: 97
};

var object2 = {
    banana: {
        price: 200
    },
    durian: 100
};

var merged = extend(object1, object2);


3

एक सच्चे क्लोन विकल्प की तलाश में, मैं यहाँ पर हास्यास्पद लिंक से टकरा गया:

http://my.opera.com/GreyWyvern/blog/show.dml/1725165

मैंने उस पृष्ठ पर समाधान को संशोधित किया, ताकि Objectप्रोटोटाइप से जुड़ा फ़ंक्शन उल्लेखनीय न हो। यहाँ मेरा परिणाम है:

Object.defineProperty(Object.prototype, 'clone', {
    enumerable: false,
    value: function() {
        var newObj = (this instanceof Array) ? [] : {};
        for (i in this) {
        if (i == 'clone') continue;
            if (this[i] && typeof this[i] == "object") {
                newObj[i] = this[i].clone();
            } else newObj[i] = this[i]
        } return newObj;
    }
});

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


ये गलत है। दिनांक प्रकार ऑब्जेक्ट है इसलिए यह कोड रिक्त ऑब्जेक्ट द्वारा दिनांक बदल देगा ... इसका उपयोग न करें।
jtblin

3

Y'all पीड़ा अभी तक समाधान सरल है।

var obj1 = {x: 5, y:5};

var obj2 = {...obj1}; // बूम



0

यदि आप कॉफी-स्क्रिप्ट का उपयोग कर रहे हैं, तो यह उतना आसान है:

newObject = {}
newObject[key] = value  for own key,value of oldObject

हालांकि यह एक गहरा क्लोन नहीं है।


0

उत्तर में से कोई भी मुझे संतुष्ट नहीं करता है, कई काम नहीं करते हैं या सिर्फ उथले क्लोन हैं, @ क्लिंट-हैरिस के जवाब और JSON.parse / stringify का उपयोग करना अच्छा है लेकिन काफी धीमी है। मुझे एक मॉड्यूल मिला जो गहरी क्लोनिंग तेजी से करता है: https://github.com/AlexeyKupershtokh/node-v8-clone


0

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

यहाँ कोड है:

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

/**
 * 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://stackoverflow.com/a/11621004/560114
 */ 
function deepCopy = function deepCopy(src, /* INTERNAL */ _visited) {
    if(src == null || typeof(src) !== 'object'){
        return src;
    }

    // Initialize the visited objects array if needed
    // This is used to detect cyclic references
    if (_visited == undefined){
        _visited = [];
    }
    // Ensure src has not already been visited
    else {
        var i, len = _visited.length;
        for (i = 0; i < len; i++) {
            // If src was already visited, don't try to copy it, just return the reference
            if (src === _visited[i]) {
                return src;
            }
        }
    }

    // Add this object to the visited array
    _visited.push(src);

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

    //Special cases:
    //Array
    if (Object.prototype.toString.call(src) == '[object Array]') {
        //[].slice(0) would soft clone
        ret = src.slice();
        var i = ret.length;
        while (i--){
            ret[i] = deepCopy(ret[i], _visited);
        }
        return ret;
    }
    //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);
    }

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

    //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 ret = object_create(proto);

    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
        ret[key] = deepCopy(src[key], _visited);
    }
    return ret;
};

0
npm install node-v8-clone

सबसे तेज क्लोनर, यह नोड.जेएस से देशी क्लोन विधि को खोलता है

var clone = require('node-v8-clone').clone;
var newObj = clone(obj, true); //true - deep recursive clone

0

एक और उपाय का उपयोग करके नए चर में सीधे एनकैप्सुलेट करना है: obj1= {...obj2}


यह एक उथली प्रति है
Rémi Doolaeghe

0

आप इस क्लोन लाइब्रेरी का उपयोग गहरी क्लोन ऑब्जेक्ट्स के लिए भी कर सकते हैं।

 npm install --save clone
const clone = require('clone');

const clonedObject = clone(sourceObject);

-2

आप हर बार जब आप उपयोग करना चाहते हैं और ऑब्जेक्ट बदलना चाहते हैं तो आप ऑब्जेक्ट ऑब्जेक्ट को प्रोटोटाइप कर सकते हैं और कॉल कर सकते हैं:

function object () {
  this.x = 5;
  this.y = 5;
}
var obj1 = new object();
var obj2 = new object();
obj2.x = 6;
console.log(obj1.x); //logs 5

आप ऑब्जेक्ट कंस्ट्रक्टर के लिए तर्क भी पास कर सकते हैं

function object (x, y) {
   this.x = x;
   this.y = y;
}
var obj1 = new object(5, 5);
var obj2 = new object(6, 6);
console.log(obj1.x); //logs 5
console.log(obj2.x); //logs 6

आशा है कि यह उपयोगी है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.