क्या यह ES6 में किसी वस्तु को क्लोन करने का एक अच्छा तरीका है?


155

"जावास्क्रिप्ट क्लोन ऑब्जेक्ट" के लिए Googling कुछ वास्तव में अजीब परिणाम लाता है, उनमें से कुछ निराशाजनक रूप से पुराने हैं और कुछ बस बहुत जटिल हैं, यह उतना आसान नहीं है:

let clone = {...original};

क्या इसमें कुछ गलत है?


1
यह कानूनी ES6 नहीं है। लेकिन अगर यह थे, तो यह एक क्लोन नहीं है: आपके क्लोन और मूल गुण दोनों एक ही चीज़ की ओर इशारा करते हैं। उदाहरण के लिए, original = { a: [1,2,3] }आपको clone.aशाब्दिक रूप से एक क्लोन देता है original.a। किसी भी चीज़ के माध्यम से संशोधन cloneया एक ही चीज़original को संशोधित करता है , इसलिए नहीं, यह बुरा है =)
माइक 'पोमैक्स' कमरमन्स

2
@AlbertoRivera यह थोड़े मान्य जावास्क्रिप्ट है, कि यह एक मंच 2 प्रस्ताव है जो जावास्क्रिप्ट मानक के लिए एक भविष्य के अतिरिक्त होने की संभावना है।
1

@Frxstrem के सवाल के साथ ES6 के बारे में, यह मान्य नहीं है जावास्क्रिप्ट =)
माइक 'पोमैक्स' कमरमन्स

3
उथला या गहरा क्लोनिंग?
फेलिक्स क्लिंग

2
आप सही हैं, यह ES6 मान्य नहीं है, यह मान्य ES9 हैdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
mikemaccana

जवाबों:


240

यह उथली क्लोनिंग के लिए अच्छा है । वस्तु प्रसार ECMAScript 2018 के एक मानक हिस्सा है

गहरी क्लोनिंग के लिए आपको एक अलग समाधान की आवश्यकता होगी ।

const clone = {...original} उथले क्लोन

const newobj = {...original, prop: newOne} मूल रूप से एक और प्रोप जोड़ने के लिए और एक नई वस्तु के रूप में संग्रहीत करने के लिए


18
हालांकि, यह सिर्फ एक उथले क्लोन नहीं है? के रूप में, गुण पुनरावर्ती क्लोन नहीं हैं, वे हैं? इसलिए, original.innerObject === clone.innerObject और बदलते मूल.innerObject.property से बदल जाएगा clone.innerObject.property।
मिलनियो

18
हाँ, यह एक उथला क्लोन है। यदि आप एक गहरा क्लोन चाहते हैं, तो आपको उपयोग करना होगाJSON.parse(JSON.stringify(input))
मार्क शस्ट एम। एकेडमी

8
/! \ JSON.parse (JSON.stringify (इनपुट)) तारीखें अपरिभाषित करता है, अपरिभाषित ... यह क्लोनिंग के लिए चांदी की गोली नहीं है! देखें: maxpou.fr/immutability-js-without-library
Guillaume

1
तो क्या हैक हैक JSON.stringify () / JSON.parse () वास्तव में ES6 में किसी ऑब्जेक्ट को गहरी क्लोन करने के लिए अनुशंसित तरीका है? मैं इसे अनुशंसित देख रहा हूं। परेशान।
सोलविटिग

3
@MarkShust JSON.parse(JSON.stringify(input))काम नहीं करेगा, क्योंकि अगर वहाँ functionsया infinityमूल्यों के रूप में यह बस nullउनके स्थान पर असाइन किया जाएगा । यह तभी काम करेगा जब मूल्य सरल हों literalsऔर न हों functions
बैकस्लैश

66

EDIT: जब यह उत्तर पोस्ट किया गया था, तो {...obj}अधिकांश ब्राउज़रों में सिंटैक्स उपलब्ध नहीं था। आजकल, आपको इसका उपयोग करना चाहिए (जब तक कि आपको IE 11 का समर्थन करने की आवश्यकता न हो)।

ऑब्जेक्ट का उपयोग करें।

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

हालाँकि, यह एक गहरा क्लोन नहीं बनाएगा। अभी तक गहरी क्लोनिंग का कोई देशी तरीका नहीं है।

संपादित करें: जैसा कि @Mike 'पोमैक्स' कमरमन्स ने टिप्पणियों में उल्लेख किया है, आप सरल वस्तुओं (यानी कोई प्रोटोटाइप, फ़ंक्शन या परिपत्र संदर्भ) का उपयोग करके गहरी क्लोन कर सकते हैं। JSON.parse(JSON.stringify(input))


19
एक है, बशर्ते आपकी वस्तु एक सच्ची वस्तु शाब्दिक और विशुद्ध रूप से डेटा है, जिस स्थिति JSON.parse(JSON.stringify(input))में एक उचित गहरा क्लोन है। हालाँकि, पल प्रोटोटाइप, कार्य या परिपत्र संदर्भ खेल में हैं, यह समाधान अब काम नहीं करता है।
माइक 'पोमैक्स' कामेरमेंस

@ माइक'पोमैक्स'कमरमंस यह सच है। गेटर्स और सेटर्स के लिए कार्यक्षमता खोना भयानक है, हालांकि ...
अल्बर्टो रिवेरा

यदि आपको किसी भी ऑब्जेक्ट को गहरी क्लोन करने के लिए एक सामान्य फ़ंक्शन की आवश्यकता है, तो stackoverflow.com/a/13333781/560114 देखें
मैट ब्राउन ने

1
अब मूल रूप से गहरी क्लोनिंग करने का एक तरीका है ।
Dan Dascalescu

1
@DanDascalescu भले ही प्रायोगिक है, यह काफी आशाजनक लगता है। जानकारी के लिए धन्यवाद!
अल्बर्टो रिवेरा

4

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

आयात _

import * as _ from 'lodash';

गहरी क्लोन वस्तु

myObjCopy = _.cloneDeep(myObj);

बस import _ from 'lodash';पर्याप्त है। लेकिन +1 के लिए "पहिया को मजबूत न करें" उत्तर।
rustyx

लॉश फूला हुआ है। वास्तव में सिर्फ एक साधारण गहरी नकल के लिए लताड़ में खींचने की जरूरत नहीं है। यहां अन्य समाधान के बहुत सारे। यह एक दुबला एप्लिकेशन बनाने के लिए देख रहे वेब डेवलपर्स के लिए एक बहुत बुरा जवाब है।
जेसन राइस

3

अगर आप json.parse (json.stringify (ऑब्जेक्ट)) का उपयोग नहीं करना चाहते हैं, तो आप पुनरावर्ती कुंजी-मूल्य प्रतियां बना सकते हैं:

function copy(item){
  let result = null;
  if(!item) return result;
  if(Array.isArray(item)){
    result = [];
    item.forEach(element=>{
      result.push(copy(element));
    });
  }
  else if(item instanceof Object && !(item instanceof Function)){ 
    result = {};
    for(let key in item){
      if(key){
        result[key] = copy(item[key]);
      }
    }
  }
  return result || item;
}

लेकिन सबसे अच्छा तरीका यह है कि एक ऐसा वर्ग तैयार किया जाए जो स्वयं का क्लोन लौटा सके

class MyClass{
    data = null;
    constructor(values){ this.data = values }
    toString(){ console.log("MyClass: "+this.data.toString(;) }
    remove(id){ this.data = data.filter(d=>d.id!==id) }
    clone(){ return new MyClass(this.data) }
}

2

@ उमरसेल के जवाब के बाद मैंने पाया कि कुछ कार्य अभी भी क्लोन किए गए ऑब्जेक्ट पर गायब थे। जैसे

function MyObject() {
  var methodAValue = null,
      methodBValue = null

  Object.defineProperty(this, "methodA", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    },
    enumerable: true
  });

  Object.defineProperty(this, "methodB", {
    get: function() { return methodAValue; },
    set: function(value) {
      methodAValue = value || {};
    }
  });
}

जहां MyObject पर मैं मेथड क्लोन कर सकता था, लेकिन मेथडब को बाहर रखा गया था। ऐसा इसलिए हुआ क्योंकि यह गायब है

enumerable: true

जिसका मतलब था कि यह नहीं दिखा

for(let key in item)

इसके बजाय मैंने स्विच ऑन किया

Object.getOwnPropertyNames(item).forEach((key) => {
    ....
  });

जिसमें गैर-गणना योग्य कुंजियाँ शामिल होंगी।

मैंने यह भी पाया कि प्रोटोटाइप ( प्रोटो ) को क्लोन नहीं किया गया था। उसके लिए मैंने प्रयोग करना समाप्त कर दिया

if (obj.__proto__) {
  copy.__proto__ = Object.assign(Object.create(Object.getPrototypeOf(obj)), obj);
}

पुनश्च: यह देखते हुए कि मुझे ऐसा करने के लिए एक निर्मित फ़ंक्शन नहीं मिला।


1

आप इसे इस तरह से भी कर सकते हैं,

let copiedData = JSON.parse(JSON.stringify(data));

-1
We can do that with two way:
1- First create a new object and replicate the structure of the existing one by iterating 
 over its properties and copying them on the primitive level.

let user = {
     name: "John",
     age: 30
    };

    let clone = {}; // the new empty object

    // let's copy all user properties into it
    for (let key in user) {
      clone[key] = user[key];
    }

    // now clone is a fully independant clone
    clone.name = "Pete"; // changed the data in it

    alert( user.name ); // still John in the original object

2- Second we can use the method Object.assign for that 
    let user = { name: "John" };
    let permissions1 = { canView: true };
    let permissions2 = { canEdit: true };

    // copies all properties from permissions1 and permissions2 into user
    Object.assign(user, permissions1, permissions2);

  -Another example

    let user = {
      name: "John",
      age: 30
    };

    let clone = Object.assign({}, user);
It copies all properties of user into the empty object and returns it. Actually, the same as the loop, but shorter.

लेकिन Object.assign () एक गहरा क्लोन नहीं बनाता है

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};

let clone = Object.assign({}, user);

alert( user.sizes === clone.sizes ); // true, same object

// user and clone share sizes
user.sizes.width++;       // change a property from one place
alert(clone.sizes.width); // 51, see the result from the other one

इसे ठीक करने के लिए, हमें क्लोनिंग लूप का उपयोग करना चाहिए जो उपयोगकर्ता [कुंजी] के प्रत्येक मूल्य की जांच करता है और, यदि यह एक वस्तु है, तो इसकी संरचना को भी दोहराएं। इसे "डीप क्लोनिंग" कहा जाता है।

गहरी क्लोनिंग के लिए एक मानक एल्गोरिथ्म है जो ऊपर और अधिक जटिल मामलों को संभालता है, जिसे स्ट्रक्चर्ड क्लोनिंग एल्गोरिदम कहा जाता है । पहिया को सुदृढ़ नहीं करने के लिए, हम जावास्क्रिप्ट लाइब्रेरी से इसकी कार्यशील क्रियान्वयन का उपयोग कर सकते हैं, इस विधि को दर्ज करने के लिए _.cloneDeep (obj) कहा जाता है ।


-1

ऊपर दिए गए सभी तरीके ऑब्जेक्ट की गहरी क्लोनिंग को हैंडल नहीं करते हैं जहां इसे एन स्तरों तक पहुंचाया जाता है। मैंने दूसरों पर इसके प्रदर्शन की जांच नहीं की, लेकिन यह छोटा और सरल है।

नीचे दिया गया पहला उदाहरण ऑब्जेक्ट क्लोनिंग का उपयोग करके दिखाता है Object.assignकि पहले स्तर तक कौन से क्लोन हैं।

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

newPerson = Object.assign({},person);
newPerson.skills.lang = 'angular';
console.log(newPerson.skills.lang); //logs Angular

नीचे दिए गए दृष्टिकोण का उपयोग करते हुए गहरी क्लोन ऑब्जेक्ट

var person = {
    name:'saksham',
    age:22,
    skills: {
        lang:'javascript',
        experience:5
    }
}

anotherNewPerson = JSON.parse(JSON.stringify(person));
anotherNewPerson.skills.lang = 'angular';
console.log(person.skills.lang); //logs javascript


JSON.parse / stringify को वर्षों से खराब गहरी क्लोनिंग विधि के रूप में उल्लेख किया गया है । कृपया पिछले उत्तर और साथ ही संबंधित प्रश्नों की जाँच करें। इसके अलावा, यह ES6 के लिए नया नहीं है।
Dan Dascalescu

@DanDascalescu मुझे यह पता है और मुझे लगता है कि इसे साधारण वस्तुओं के लिए उपयोग करने का मुद्दा नहीं होना चाहिए। दूसरों ने भी अपने उत्तर में इसी पोस्ट में और यहां तक ​​कि टिप्पणियों के रूप में भी इसका उल्लेख किया है। मुझे लगता है कि यह एक पतन के लायक नहीं है।
साक्षाम

बिल्कुल - "अन्य ने भी अपने उत्तर में JSON.parse / stringify का उल्लेख किया है।" क्यों एक ही समाधान के साथ एक और उत्तर पोस्ट करें?
दान डैस्कलेस्कु
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.