कैसे एक जावास्क्रिप्ट ES6 वर्ग उदाहरण क्लोन करने के लिए


96

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

मैं jquery या $ विस्तार पर आधारित समाधानों में दिलचस्पी नहीं रखता।

मैंने ऑब्जेक्ट क्लोनिंग की काफी पुरानी चर्चाएँ देखी हैं, जो बताती हैं कि समस्या काफी जटिल है, लेकिन ES6 के साथ एक बहुत ही सरल समाधान स्वयं प्रस्तुत करता है - मैं इसे नीचे रखूंगा और देखूंगा कि लोग इसे संतोषजनक मानते हैं या नहीं।

संपादित करें: यह सुझाव दिया जा रहा है कि मेरा प्रश्न डुप्लिकेट है; मैंने उस उत्तर को देखा, लेकिन यह 7 साल पुराना है और इसमें पूर्व-ईएस 6 जेएस का उपयोग करके बहुत ही जटिल उत्तर शामिल हैं। मैं सुझाव दे रहा हूं कि मेरा प्रश्न, जो ईएस 6 के लिए अनुमति देता है, में नाटकीय रूप से सरल समाधान है।


2
यदि आपके पास स्टैक ओवरफ्लो पर एक पुराने प्रश्न का एक नया उत्तर है, तो कृपया उस प्रश्न को मूल प्रश्न में जोड़ें, बस एक नया प्रश्न न बनाएं।
हेरिटेज मंकी

1
मुझे लगता है कि समस्या है टॉम का सामना करना पड़ रहा है क्योंकि ES6 वर्ग के उदाहरण "नियमित" वस्तुओं से अलग काम करते हैं।
चेरीनर्ड

2
इसके अलावा, स्वीकृत उत्तर में कोड का पहला टुकड़ा आपके "संभावित डुप्लिकेट" वास्तव में क्रैश प्रदान करता है जब मैं इसे ES6 वर्ग के एक उदाहरण पर चलाने की कोशिश करता हूं
चेरीनेट

मुझे लगता है कि यह कोई डुप्लिकेट नहीं है, क्योंकि ईएस 6 वर्ग उदाहरण एक वस्तु है, न कि प्रत्येक वस्तु ईएस 6 कक्षा उदाहरण है और इसलिए दूसरा प्रश्न इस प्रश्न के मुद्दे को संबोधित नहीं करता है।
टॉम ज़ातो -

5
यह कोई नकल नहीं है। अन्य प्रश्न Objectडेटा धारकों के रूप में उपयोग किए जाने वाले शुद्ध एस के बारे में था । यह एक ES6 classes के बारे में है और वर्ग प्रकार की जानकारी नहीं खोने की समस्या है। इसके लिए अलग समाधान की जरूरत है।
फ्लोरी

जवाबों:


111

यह जटिल है; मैंने बहुत कोशिश की! अंत में, इस एक-लाइनर ने मेरे कस्टम ES6 वर्ग उदाहरणों के लिए काम किया:

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

यह प्रोटोटाइप स्थापित करने से बचता है क्योंकि वे कहते हैं कि यह कोड को बहुत धीमा कर देता है।

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

निष्कर्ष: यह एक गड़बड़ है। चलो आशा करते हैं कि एक दिन एक देशी और स्वच्छ क्लोन कार्यक्षमता होगी।


1
यह स्थैतिक तरीकों की नकल नहीं करेगा, क्योंकि वे वास्तव में स्वयं के गुणों के योग्य नहीं हैं।
श्री लवलमप

5
@ Mr.Lavalamp और आप कैसे (भी) स्थैतिक तरीकों की नकल कर सकते हैं?
फ्लोरी डेसी

यह सरणियों को नष्ट कर देगा! यह "0", "1", ... कुंजियों के साथ सभी सरणियों को वस्तुओं में परिवर्तित कर देगा।
वाहिद

1
@KeshaAntonov आप टाइपोफ़ और एरे तरीकों के साथ एक समाधान खोजने में सक्षम हो सकते हैं। मैं स्वयं सभी प्रॉपर्टी को मैन्युअल रूप से क्लोन करना पसंद करता था।
वाहिद

1
यह उम्मीद मत करो कि यह उन गुणों को क्लोन करने के लिए है जो स्वयं ऑब्जेक्ट हैं: jsbin.com/qeziwetexu/edit?js,console
jduhls

10
const clone = Object.assign( {}, instanceOfBlah );
Object.setPrototypeOf( clone, Blah.prototype );

Object.assign की विशेषताओं पर ध्यान दें : यह एक उथले कॉपी करता है और क्लास के तरीकों की नकल नहीं करता है।

यदि आप प्रतिलिपि पर एक गहरी प्रतिलिपि या अधिक नियंत्रण चाहते हैं तो लॉश क्लोन कार्य हैं


2
चूंकि Object.createनिर्दिष्ट प्रोटोटाइप के साथ नई वस्तु बनाता है, तो बस क्यों नहीं const clone = Object.assign(Object.create(instanceOfBlah), instanceOfBlah)। साथ ही क्लास के तरीकों को भी कॉपी किया जाएगा।
बारबेटस

1
@barbatus हालांकि, गलत प्रोटोटाइप का उपयोग करता है Blah.prototype != instanceOfBlah। आप का उपयोग करना चाहिएObject.getPrototypeOf(instanceOfBlah)
Bergi

1
@Bergi नहीं, ES6 वर्ग उदाहरण में हमेशा एक प्रोटोटाइप नहीं होता है। की जाँच करें codepen.io/techniq/pen/qdZeZm है कि यह भी उदाहरण के साथ काम करता है।
बारबेटस

@barbatus क्षमा करें, क्या? मैं अनुसरण नहीं करता। सभी उदाहरणों में एक प्रोटोटाइप है, यही उन्हें उदाहरण देता है। कोड को फ्लोरी के उत्तर से आज़माएं।
बरगी

1
@ बर्गी मुझे लगता है कि यह बैबल कॉन्फ़िगरेशन या कुछ और पर निर्भर करता है। मैं अभी एक प्रतिक्रियाशील देशी ऐप को लागू कर रहा हूं और कोई विरासत में मिली संपत्ति के साथ उदाहरणों में प्रोटोटाइप नल नहीं है। जैसा कि आप यहां पर देख सकते हैं। developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… यह संभव है कि getPrototypeOf रिटर्न शून्य हो।
बारबेटस

3

यह प्रोटोटाइप के एक्सटेंशन बनाने के लिए अनुशंसित नहीं है, यह उन मुद्दों के परिणामस्वरूप होगा जब आप अपने कोड / घटकों पर परीक्षण करेंगे। इकाई परीक्षण चौखटे स्वचालित रूप से आपके प्रोटोटाइप एक्सटेंशन को नहीं मानेंगे। तो यह एक अच्छा अभ्यास नहीं है। यहां प्रोटोटाइप एक्सटेंशन के अधिक स्पष्टीकरण हैं क्यों देशी वस्तुओं को एक बुरी प्रथा का विस्तार किया जा रहा है?

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

1 -> उथला क्लोन:

class Employee {
    constructor(first, last, street) {
        this.firstName = first;
        this.lastName = last;
        this.address = { street: street };
    }

    logFullName() {
        console.log(this.firstName + ' ' + this.lastName);
    }
}

let original = new Employee('Cassio', 'Seffrin', 'Street A, 23');
let clone =  Object.assign({},original); //object.assing() method
let cloneWithPrototype Object.create(Object.getPrototypeOf(original)), original) //  the clone will inherit the prototype methods of the original.
let clone2 = { ...original }; // the same of object assign but shorter sintax using "spread operator"
clone.firstName = 'John';
clone.address.street = 'Street B, 99'; //will not be cloned

परिणाम:

original.logFullName ():

परिणाम: कैसियो सेफिन

clone.logFullName ():

परिणाम: जॉन सेफेन

original.address.street;

परिणाम: 'स्ट्रीट बी, 99' // ध्यान दें कि मूल उप ऑब्जेक्ट को बदल दिया गया था

सूचना: यदि उदाहरण के पास स्वयं के गुणों के रूप में बंद है, तो यह विधि इसे लपेटेगी नहीं। ( बंद के बारे में अधिक पढ़ें ) और प्लस, उप ऑब्जेक्ट "पता" क्लोन नहीं किया जाएगा।

clone.logFullName ()

काम नहीं करेगा।

cloneWithPrototype.logFullName ()

काम करेगा, क्योंकि क्लोन इसके प्रोटोटाइप को भी कॉपी करेगा।

Object.assign के साथ सरणियों को क्लोन करने के लिए:

let cloneArr = array.map((a) => Object.assign({}, a));

ECMAScript प्रसार सिंटैक्स का उपयोग करके क्लोन सरणी:

let cloneArrSpread = array.map((a) => ({ ...a }));

2 -> गहरा क्लोन:

एक पूरी तरह से नए ऑब्जेक्ट संदर्भ को संग्रहीत करने के लिए हम JSON.stringify () को मूल ऑब्जेक्ट को स्ट्रिंग के रूप में पार्स करने के लिए उपयोग कर सकते हैं और इसे JSON.parse () में वापस पार्स करने के बाद।

let deepClone = JSON.parse(JSON.stringify(original));

गहरे क्लोन के साथ संबोधन के संदर्भ रखे जाएंगे। हालांकि डीपक्लोन प्रोटोटाइप को बंद कर दिया जाएगा, इसलिए डीपक्लोन.लॉगफुलनाम () काम नहीं करेगा।

3 -> 3 पार्टी पुस्तकालय:

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

अंडरस्कोर: चलो क्लोनडॉर्स्कोर = _ (मूल) .clone ();

लोडश क्लोन: var cloneLodash = _.cloneDeep (मूल);

लॉश या अंडरस्कोर के नकारात्मक पहलू को आपकी परियोजना में कुछ अतिरिक्त पुस्तकालयों को शामिल करने की आवश्यकता थी। हालांकि वे अच्छे विकल्प हैं और उच्च प्रदर्शन परिणाम भी देते हैं।


1
जब असाइन किया जाता है {}, तो क्लोन मूल के किसी भी प्रोटोटाइप तरीके को इनहेरिट नहीं करेगा। clone.logFullName()बिलकुल नहीं चलेगा। Object.assign( Object.create(Object.getPrototypeOf(eOriginal)), eOriginal)इससे पहले कि आप ठीक था, तुम क्यों कि बदल दिया?
बरगी

1
@Bergi आपके योगदान के लिए धन्यवाद, मैं अभी अपना उत्तर संपादित कर रहा था, मैंने आपकी बात को प्रोटोटाइप कॉपी करने के लिए जोड़ दिया!
कैसियो सेफ्रिन

1
मैं आपकी मदद की सराहना करता हूं @ बर्गी, कृपया अपनी राय दें। मैंने संस्करण समाप्त कर दिया है। मुझे लगता है कि अब उत्तर ने लगभग सभी सवालों को कवर कर दिया है। Thks!
कैसियो सेफिन

1
हां, और बस Object.assign({},original), यह काम नहीं करता है।
बरगी

1
कभी-कभी सरल दृष्टिकोण हम सभी की आवश्यकता होती है। यदि आपको प्रोटोटाइप और जटिल वस्तुओं की आवश्यकता नहीं है, तो बस "क्लोन = {... मूल}" समस्या को हल कर सकते हैं
कैसियो सेफ्रीन

0

एक और एक लाइनर:

अधिकांश समय ... (दिनांक, RegExp, मैप, स्ट्रिंग, संख्या, सरणी के लिए काम करता है), btw, स्ट्रिंग स्ट्रिंग, संख्या थोड़ी अजीब है।

let clone = new obj.constructor(...[obj].flat())

कॉपी कंस्ट्रक्टर के बिना उन वर्ग के लिए:

let clone = Object.assign(new obj.constructor(...[obj].flat()), obj)

0
class A {
  constructor() {
    this.x = 1;
  }

  y() {
    return 1;
  }
}

const a = new A();

const output = Object.getOwnPropertyNames(Object.getPrototypeOf(a)).concat(Object.getOwnPropertyNames(a)).reduce((accumulator, currentValue, currentIndex, array) => {
  accumulator[currentValue] = a[currentValue];
  return accumulator;
}, {});

यहाँ छवि विवरण दर्ज करें


-4

उदाहरण के लिए, यदि आप ओब्ज नामक एक वस्तु का क्लोन बनाना चाहते हैं, तो आप प्रसार ऑपरेटर का उपयोग कर सकते हैं:

let clone = { ...obj};

और यदि आप क्लोन किए गए ऑब्जेक्ट में कुछ भी बदलना या जोड़ना चाहते हैं:

let clone = { ...obj, change: "something" };
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.