मूल्य द्वारा कॉपी सरणी


1744

जावास्क्रिप्ट में एक सरणी को दूसरे सरणी में कॉपी करते समय:

var arr1 = ['a','b','c'];
var arr2 = arr1;
arr2.push('d');  //Now, arr1 = ['a','b','c','d']

मैंने महसूस किया कि नए, स्वतंत्र सरणी के बजाय arr2उसी सरणी को संदर्भित करता है arr1। मैं दो स्वतंत्र सरणियों को प्राप्त करने के लिए सरणी की प्रतिलिपि कैसे बना सकता हूं?


3
ऐसा लगता है कि वर्तमान में क्रोम 53 और फ़ायरफ़ॉक्स 48 में हमारे पास अच्छे प्रदर्शन sliceऔर spliceसंचालन और नए प्रसार ऑपरेटर हैं और Array.fromबहुत धीमी गति से कार्यान्वयन है। Perfjs.fnfo
पेनक्रॉफ

jsben.ch/#/wQ9RU <= यह बेंचमार्क किसी सरणी को कॉपी करने के विभिन्न तरीकों पर एक सिंहावलोकन देता है
एस्केपनेट


इस सरणी (एक है कि आदिम तार शामिल हैं) के लिए आप उपयोग कर सकते हैं var arr2 = arr1.splice();गहरी प्रतिलिपि करने के लिए, लेकिन इस तकनीक अगर काम नहीं अपने सरणी में तत्वों शाब्दिक संरचनाओं (यानी शामिल होंगे []या {}) या प्रोटोटाइप वस्तुओं (यानी function () {}, new, आदि)। आगे के समाधान के लिए नीचे मेरा जवाब देखें।
tfmontague

16
यह 2017 है, इसलिए आप ES6 सुविधाओं का उपयोग करने पर विचार कर सकते हैं: let arr2 = [...arr1]; developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Hinrich

जवाबों:


2700

इसे इस्तेमाल करो:

var newArray = oldArray.slice();

असल में, slice()ऑपरेशन सरणी को क्लोन करता है और एक नए सरणी के लिए एक संदर्भ देता है।

यह भी ध्यान दें:

संदर्भ, तार और संख्या (और वास्तविक वस्तु नहीं) के लिए, slice()नए संदर्भ में ऑब्जेक्ट संदर्भ को कॉपी करता है। मूल और नए दोनों सरणी एक ही वस्तु को संदर्भित करते हैं। यदि एक संदर्भित ऑब्जेक्ट बदलता है, तो परिवर्तन नए और मूल दोनों सरणियों को दिखाई देते हैं।

स्ट्रिंग्स और संख्याओं जैसे प्राइमिटिव अपरिवर्तनीय हैं, इसलिए स्ट्रिंग या संख्या में परिवर्तन असंभव है।


9
प्रदर्शन के बारे में निम्नलिखित jsPerf परीक्षण वास्तव में दिखाते हैं कि var arr2 = arr1.slice () var arr2 = arr1.concat () के समान ही तेज़ है; JSPerf: jsperf.com/copy-array-slice-vs-concat/5 और jsperf.com/copy-simple-arrayJsperf.com/array-copy/5 के परिणाम ने मुझे इस बात पर आश्चर्यचकित कर दिया कि मैं सोच रहा हूं कि क्या परीक्षण कोड मान्य है।
कोहेन

94
भले ही यह पहले से ही एक टन तक बढ़ गया है, यह एक और हकदार है क्योंकि यह जेएस में संदर्भों का ठीक से वर्णन करता है, जो कि दुर्भाग्य से दुर्लभ है।
वेन

34
@ GáborImre आप केवल पठनीयता के लिए पूरी लाइब्रेरी जोड़ेंगे? वास्तव में? अगर मैं पठनीयता के लिए चिंतित हूं तो मैं सिर्फ एक टिप्पणी जोड़ूंगा। देखें: var newArray = oldArray.slice (); // क्लोन ओल्डएरे टू न्यूअयरे
ड्यूडेवेड

12
@ GáborImre मुझे वह मिलता है, निश्चित। लेकिन मेरी राय में एक पूरे पुस्तकालय को शामिल करके एक विशिष्ट इंजीनियरिंग समस्या का जवाब देना उपयोगी नहीं है, यह डिज़ाइन ब्लोट है। मुझे लगता है कि डेवलपर्स बहुत कुछ करते हैं, और फिर आप एक परियोजना के साथ समाप्त होते हैं जिसमें एक एकल फ़ंक्शन लिखने के लिए बदलने के लिए एक संपूर्ण रूपरेखा शामिल होती है। हालांकि मेरे मो।
दुबेवेद

5
सबक सीखा: .slice()साथ भ्रमित मत करो .splice(), जो आपको एक खाली सरणी देता है। बड़ा अंतर।
crazypeter

530

जावास्क्रिप्ट में, गहरी-कॉपी तकनीक एक सरणी में तत्वों पर निर्भर करती है। चलो वहाँ शुरू करते हैं।

तीन प्रकार के तत्व

तत्व हो सकते हैं: शाब्दिक मूल्य, शाब्दिक संरचनाएं या प्रोटोटाइप।

// Literal values (type1)
const booleanLiteral = true;
const numberLiteral = 1;
const stringLiteral = 'true';

// Literal structures (type2)
const arrayLiteral = [];
const objectLiteral = {};

// Prototypes (type3)
const booleanPrototype = new Bool(true);
const numberPrototype = new Number(1);
const stringPrototype = new String('true');
const arrayPrototype = new Array();
const objectPrototype = new Object(); // or `new function () {}`

इन तत्वों से हम तीन प्रकार के एरेज़ बना सकते हैं।

// 1) Array of literal-values (boolean, number, string) 
const type1 = [true, 1, "true"];

// 2) Array of literal-structures (array, object)
const type2 = [[], {}];

// 3) Array of prototype-objects (function)
const type3 = [function () {}, function () {}];

डीप कॉपी तकनीक तीन सरणी प्रकारों पर निर्भर करती है

सरणी में तत्वों के प्रकारों के आधार पर, हम विभिन्न तकनीकों का उपयोग गहरी प्रतिलिपि बनाने के लिए कर सकते हैं।

तत्व प्रकारों द्वारा जावास्क्रिप्ट गहरी प्रतिलिपि तकनीक

  • शाब्दिक-मूल्यों (type1) की सरणी , , , और तकनीकों केवल शाब्दिक मूल्यों (बूलियन, संख्या, और स्ट्रिंग) के साथ गहरी प्रतिलिपि सरणियों के लिए इस्तेमाल किया जा सकता है; जहां स्प्रेड ऑपरेटर का सबसे अच्छा प्रदर्शन ( https://measurethat.net/Benchmark/Show/4281/0/spread-array-performance-vs-slice-splice-concat ) है।
    [...myArray]myArray.splice(0)myArray.slice()myArray.concat()[...myArray]

  • शाब्दिक-मूल्यों (type1) और शाब्दिक संरचनाओं (type2) की सरणी तकनीक गहरी प्रतिलिपि शाब्दिक मूल्यों (बूलियन, अंक, स्ट्रिंग) और शाब्दिक संरचनाओं (सरणी, वस्तु) के लिए इस्तेमाल किया जा सकता है लेकिन वस्तुओं प्रोटोटाइप नहीं।
    JSON.parse(JSON.stringify(myArray))

  • सभी सरणियाँ (टाइप 1, टाइप 2, टाइप 3)
    jQuery $.extend(myArray)तकनीक का उपयोग सभी प्रकार के प्रकारों को डीप-कॉपी करने के लिए किया जा सकता है। अंडरस्कोर और लो-डैश जैसे पुस्तकालय jQuery के समान गहरी-कॉपी फ़ंक्शन प्रदान करते हैं $.extend(), फिर भी उनका प्रदर्शन कम है। अधिक आश्चर्यजनक रूप $.extend()से, JSON.parse(JSON.stringify(myArray))तकनीक http://jsperf.com/js-deep-copy/15 की तुलना में उच्च प्रदर्शन है ।
    और उन डेवलपर्स के लिए जो तीसरे पक्ष के पुस्तकालयों (जैसे jQuery) से दूर भागते हैं, आप निम्नलिखित कस्टम फ़ंक्शन का उपयोग कर सकते हैं; जिसमें $ .extend की तुलना में अधिक प्रदर्शन है, और सभी सरणियों को डीप-कॉपी करता है।

function copy(aObject) {
  if (!aObject) {
    return aObject;
  }

  let v;
  let bObject = Array.isArray(aObject) ? [] : {};
  for (const k in aObject) {
    v = aObject[k];
    bObject[k] = (typeof v === "object") ? copy(v) : v;
  }

  return bObject;
}

तो सवाल का जवाब देने के लिए ...

सवाल

var arr1 = ['a','b','c'];
var arr2 = arr1;

मैंने महसूस किया कि arr2 एक नए, स्वतंत्र सरणी के बजाय arr1 के समान सरणी को संदर्भित करता है। मैं दो स्वतंत्र सरणियों को प्राप्त करने के लिए सरणी की प्रतिलिपि कैसे बना सकता हूं?

उत्तर

क्योंकि arr1शाब्दिक मूल्यों (बूलियन, संख्या, या स्ट्रिंग) का एक सरणी है, आप ऊपर चर्चा की गई किसी भी गहरी प्रतिलिपि तकनीक का उपयोग कर सकते हैं, जहां प्रसार ऑपरेटर ...का उच्चतम प्रदर्शन है।

// Highest performance for deep copying literal values
arr2 = [...arr1];

// Any of these techniques will deep copy literal values as well,
//   but with lower performance.
arr2 = arr1.slice();
arr2 = arr1.splice(0);
arr2 = arr1.concat();
arr2 = JSON.parse(JSON.stringify(arr1));
arr2 = $.extend(true, [], arr1); // jQuery.js needed
arr2 = _.extend(arr1); // Underscore.js needed
arr2 = _.cloneDeep(arr1); // Lo-dash.js needed
arr2 = copy(arr1); // Custom-function needed - as provided above

1
इनमें से कई दृष्टिकोण अच्छी तरह से काम नहीं करते हैं। असाइनमेंट ऑपरेटर का उपयोग करने का मतलब है कि आपको मूल शाब्दिक मान को फिर से असाइन करना होगा arr1। यह बहुत दुर्लभ है कि यह मामला होने जा रहा है। spliceObliterates का उपयोग करना arr1, इसलिए यह एक प्रतिलिपि नहीं है। उपयोग JSONकरना विफल हो जाएगा यदि सरणी में कोई मान कार्य करता है या प्रोटोटाइप (जैसे Date) है।
दन्क्रम्ब

ब्याह का उपयोग आंशिक समाधान है। यह JSON की तुलना में कहीं अधिक मामलों में विफल हो जाएगा। स्प्लिस स्ट्रिंग्स और संख्याओं की एक गहरी प्रतिलिपि बनाता है, जब यह मूल्यों को स्थानांतरित करता है - कभी नहीं कहा कि यह एक प्रतिलिपि लौटाता है।
tfmontague

1
ब्याह (0) क्यों? क्या यह टुकड़ा () नहीं होना चाहिए? मुझे लगता है कि यह मूल सरणी को संशोधित नहीं करना चाहिए, जो ब्याह करता है। @JamesMontagne
helpse

2
ब्याह मूल सरणी (उथले प्रतिलिपि) में तत्वों को इंगित करेगा। ब्याह (0) सरणी में तत्वों के लिए नई मेमोरी (गहरी प्रतिलिपि) आवंटित करेगा जो संख्या या तार हैं, और अन्य सभी तत्व प्रकारों (उथले प्रतिलिपि) के लिए संकेत बनाते हैं। ब्याह फ़ंक्शन-विधि के लिए शून्य का एक प्रारंभ मान पारित करके, यह मूल सरणी से किसी भी तत्व को विभाजित नहीं करेगा, और इसलिए यह इसे संशोधित नहीं करता है।
tfmontague

1
वास्तव में, केवल एक प्रकार का सरणी है: "somethings" की एक सरणी। [0,"1",{2:3},function random() {return 4;}, [[5,6,7],[8,9,10],[11,12,13]]]कोई अन्य सरणी के बीच कोई अंतर नहीं है ।
wizzwizz4

189

आप ...सरणियों को कॉपी करने के लिए सरणी स्प्रेड का उपयोग कर सकते हैं ।

const itemsCopy = [...items];

इसके अलावा यदि कोई नया एरे बनाना चाहता है तो उसका एक हिस्सा होना चाहिए:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];

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

अधिक जानकारी फैलता है


1
यह गहरी प्रतिलिपि के लिए काम नहीं करेगा। दीप क्लोन ऐरे इन एरेक
SNag

151

कोई jQuery की जरूरत है ... कार्य उदाहरण

var arr2 = arr1.slice()

यह एरे को प्रारंभिक स्थिति 0से एरे के अंत तक कॉपी करता है ।

यह ध्यान रखना महत्वपूर्ण है कि यह आदिम प्रकार (स्ट्रिंग, संख्या, आदि) के लिए अपेक्षा के अनुसार काम करेगा, और संदर्भ प्रकारों के लिए अपेक्षित व्यवहार की व्याख्या करने के लिए भी ...

यदि आपके पास संदर्भ प्रकारों की एक सरणी है, तो टाइप करें Object। सरणी की प्रतिलिपि बनाई जाएगी , लेकिन दोनों सरणियों में समान के संदर्भ होंगे Object। तो इस मामले में ऐसा लगता है कि सरणी को संदर्भ द्वारा कॉपी किया गया है, भले ही सरणी वास्तव में कॉपी की गई हो।


12
नहीं, यह एक गहरी प्रति नहीं होगी।
jondavidjohn

इसे इस्तेमाल करे; var arr2 = JSON.stringify(arr1); arr2 = JSON.parse(arr2);
प्रदीप

2
इस उत्तर और स्वीकृत उत्तर में क्या अंतर है?
आइजैक पाक

आपके दिए गए उदाहरण के लिए कंसोल में त्रुटि हो रही है "TypeError: window.addEvent एक फ़ंक्शन नहीं है"
रवि शर्मा

72

का एक विकल्प sliceहै concat, जिसे 2 तरीकों से इस्तेमाल किया जा सकता है। इनमें से पहला शायद अधिक पठनीय है क्योंकि अभीष्ट व्यवहार बहुत स्पष्ट है:

var array2 = [].concat(array1);

दूसरी विधि है:

var array2 = array1.concat();

कोहेन (टिप्पणियों में) ने कहा कि इस उत्तरार्द्ध में बेहतर प्रदर्शन है

जिस तरह से यह काम करता है वह यह है कि concatविधि उस ऑब्जेक्ट में तत्वों से मिलकर एक नया सरणी बनाता है जिस पर इसे तर्क के रूप में पारित किसी भी सरणियों के तत्वों द्वारा अनुसरण किया जाता है। इसलिए जब कोई तर्क पारित नहीं किया जाता है, तो यह केवल सरणी को कॉपी करता है।

ली पेनकमैन भी टिप्पणियों में बताते हैं कि अगर कोई मौका array1है undefined, तो आप एक खाली सरणी वापस कर सकते हैं:

var array2 = [].concat(array1 || []);

या, दूसरी विधि के लिए:

var array2 = (array1 || []).concat();

ध्यान रखें कि आप के साथ ऐसा कर सकते हैं कि slice: var array2 = (array1 || []).slice();


31
वास्तव में आप यह भी कर सकते हैं: var array2 = array1.concat (); यह प्रदर्शन के बारे में बहुत तेज है। (JSPerf: jsperf.com/copy-simple-array और jsperf.com/copy-array-slice-vs-concat/5
कोहेन

5
इसके लायक ध्यान देने योग्य बात यह है कि अगर array1 एक सरणी नहीं है तो [].concat(array1)रिटर्न [array1]जैसे अगर इसकी अपरिभाषित आप मिल जाएगा [undefined]। मैं कभी कभी करते हैंvar array2 = [].concat(array1 || []);
ली penkman

60

यह मैंने कई तरीकों की कोशिश करने के बाद किया है:

var newArray = JSON.parse(JSON.stringify(orgArray));

यह एक नई गहरी प्रति बनाएगा जो पहले वाले से संबंधित नहीं है (उथली प्रति नहीं)।

इसके अलावा यह स्पष्ट रूप से घटनाओं और कार्यों को क्लोन नहीं करेगा, लेकिन अच्छी बात यह है कि आप इसे एक पंक्ति में कर सकते हैं, और इसका उपयोग किसी भी प्रकार की वस्तु (सरणियों, तारों, संख्याओं, वस्तुओं ...) के लिए किया जा सकता है।


4
यह सबसे अच्छा है। मैं एक ही विधि का उपयोग बहुत समय पहले करता हूं और सोचता हूं कि पुराने स्कूल के पुनरावर्ती छोरों में कोई अधिक समझ नहीं है
व्लादिमीर खरलमपीडी

1
ध्यान रखें कि यह विकल्प अच्छी तरह से ग्राफ़ जैसी संरचनाओं को संभालता नहीं है: चक्र की उपस्थिति में दुर्घटनाग्रस्त हो जाता है, और साझा संदर्भों को संरक्षित नहीं करता है।
Ruben

1
यह भी चीजों के लिए विफल रहता है Date, या वास्तव में, कुछ भी जो एक प्रोटोटाइप है। इसके अलावा, undefinedएस को परिवर्तित हो जाते हैं null
दांकरुम्ब

7
क्या कोई भी बहादुर नहीं है कि वह सीपीयू और पाठ को क्रमबद्ध करने और फिर किसी वस्तु पर वापस जाने की स्मृति में दोनों की सकल अक्षमता पर टिप्पणी कर सके?
लॉरेंस डोल

3
यह समाधान केवल एक ही है जो काम करता है। स्लाइस () का उपयोग करना वास्तव में एक नकली समाधान है।

20

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

अपनी जावास्क्रिप्ट फ़ाइल में निम्न कोड जोड़ें:

Object.prototype.clone = 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;
};

और बस उपयोग करें

var arr1 = ['val_1','val_2','val_3'];
var arr2 = arr1.clone()

यह काम करेगा।


2
मैं इस त्रुटि मिलती है जब मैं अपने पेज के लिए इस कोड को जोड़ने 'Uncaught RangeError: अधिकतम कॉल स्टैक आकार से अधिक हो'
Sawe

1
मेरी क्षमायाचना, यह त्रुटि क्रोम में होती है यदि एरे 1 घोषित नहीं किया जाता है। इसलिए मैंने उपरोक्त कोड को कॉपी-पेस्ट किया है, और मुझे त्रुटि मिलती है, हालांकि, अगर मैं सरणी को गिरफ्तार करता हूं 1, तो मुझे त्रुटि नहीं मिलती है। आप arr2 के ठीक ऊपर arr1 घोषित करके उत्तर को बेहतर बना सकते हैं, मैं देख रहा हूँ कि वहाँ 'हम' में से कुछ ऐसे हैं जिन्होंने यह नहीं पहचाना कि हमें arr1 घोषित करना था (आंशिक रूप से क्योंकि जब मैं आपके उत्तर का मूल्यांकन कर रहा था, मैं एक भीड़ में था और कुछ है कि 'सिर्फ काम करता है' की जरूरत है
आरा

.slice()अभी भी ठीक काम करता है, भले ही आपके पास आपके सरणी में वस्तुएं हों: jsfiddle.net/edelman/k525g
जेसन

7
@ जेसन लेकिन वस्तुएं अभी भी एक ही वस्तु की ओर इशारा कर रही हैं इसलिए एक को बदलने से दूसरे को बदल जाएगा। jsfiddle.net/k525g/1
सैमुअल

बहुत बढ़िया कोड। एक प्रश्न जो मेरे पास है, मैंने वास्तव में इस var arr1 = new Array () और फिर var arr2 = 1 s1 जैसे एक सरणी को दूसरे में कॉपी करने की कोशिश की; अगर मैं arr2 में कुछ बदलता हूं, तो परिवर्तन arr1 के लिए भी होता है। हालाँकि, यदि मैं आपके द्वारा किए गए क्लोन प्रोटोटाइप का उपयोग करता हूं, तो यह वास्तव में उस सरणी का एक नया उदाहरण या दूसरे शब्दों में इसे कॉपी करता है। तो क्या यह ब्राउज़र की समस्या है? या डिफ़ॉल्ट रूप से जावास्क्रिप्ट दो बिंदुओं को एक-दूसरे की ओर इशारा करते हुए संकेत के उपयोग के साथ सेट करता है जब कोई व्यक्ति var2 = arr1 करता है और पूर्णांक चर के साथ क्यों नहीं होता है? देख jsfiddle.net/themhz/HbhtA
themhz


17

मुझे व्यक्तिगत रूप से लगता है कि Array.from एक अधिक पठनीय समाधान है। वैसे, बस इसके ब्राउज़र समर्थन से सावधान रहें।

//clone
let x = [1,2,3];
let y = Array.from(x);

//deep clone
let clone = arr => Array.from(arr,item => Array.isArray(item) ? clone(item) : item);
let x = [1,[],[[]]];
let y = clone(x);

1
हां, यह बहुत पठनीय है। .slice()समाधान पूरी तरह से unintuitive है। इसके लिए धन्यवाद।
बनगो

15

जरूरी!

यहां अधिकांश उत्तर विशेष मामलों के लिए काम करते हैं

यदि आप गहरी / नेस्टेड वस्तुओं और प्रॉपर उपयोग ( ES6 ) की परवाह नहीं करते हैं :

let clonedArray = [...array]

लेकिन अगर आप इसके बजाय गहरे क्लोन का उपयोग करना चाहते हैं:

let cloneArray = JSON.parse(JSON.stringify(array))


दर्जकर्ता उपयोगकर्ताओं के लिए:

let clonedArray = _.clone(array) प्रलेखन

तथा

let clonedArray = _.cloneDeep(array) प्रलेखन


11

यदि आप ECMAScript 6 के वातावरण में हैं , तो स्प्रेड ऑपरेटर का उपयोग करके आप इसे इस प्रकार कर सकते हैं:

var arr1 = ['a','b','c'];
var arr2 = [...arr1]; //copy arr1
arr2.push('d');

console.log(arr1)
console.log(arr2)
<script src="http://www.wzvang.com/snippet/ignore_this_file.js"></script>


9

Array.slice () के समाधान में जोड़ना; ध्यान रखें कि यदि आपके पास बहुआयामी सरणी उप-सरणियाँ हैं, तो उन्हें संदर्भों द्वारा कॉपी किया जाएगा। आप जो कर सकते हैं वह है लूप और स्लाइस () प्रत्येक उप-सरणी को व्यक्तिगत रूप से

var arr = [[1,1,1],[2,2,2],[3,3,3]];
var arr2 = arr.slice();

arr2[0][1] = 55;
console.log(arr2[0][1]);
console.log(arr[0][1]);

function arrCpy(arrSrc, arrDis){
 for(elm in arrSrc){
  arrDis.push(arrSrc[elm].slice());
}
}

var arr3=[];
arrCpy(arr,arr3);

arr3[1][1] = 77;

console.log(arr3[1][1]);
console.log(arr[1][1]);

वही चीजें वस्तुओं के सरणी में जाती हैं, उन्हें संदर्भ द्वारा कॉपी किया जाएगा, आपको उन्हें मैन्युअल रूप से कॉपी करना होगा


यह उत्तर पृष्ठ के शीर्ष के पास एक स्थान के योग्य है! मैं बहुआयामी उप सरणियों के साथ काम कर रहा था और इस बात का पालन नहीं कर सकता था कि आंतरिक सरणियों को हमेशा रेफरी द्वारा कॉपी किया जाता था और वैल द्वारा नहीं। इस सरल तर्क ने मेरी समस्या हल कर दी। यदि संभव हो तो मैं आपको +100 दूंगा!
मैक

8

आदिम मान हमेशा इसके मूल्य (कॉपी किए हुए) से गुजरते हैं। यौगिक मूल्य हालांकि संदर्भ द्वारा पारित किए जाते हैं।

तो हम इस गिरफ्तारी की नकल कैसे करते हैं?

let arr = [1,2,3,4,5];

ES6 में एक सरणी की प्रतिलिपि बनाएँ

let arrCopy = [...arr]; 

ES5 में n सरणी को कॉपी करें

let arrCopy = arr.slice(); 
let arrCopy = [].concat(arr);

मान क्यों दें 'गिरफ्तारी = गिरफ्तारी' मूल्य से नहीं गुजर रही है?

Compound / Array जैसे यौगिक मूल्यों पर एक से दूसरे संस्करण को पास करना भिन्न व्यवहार करता है। कॉपेंड मानों पर असाइन ऑपरेटर के उपयोग से हम किसी ऑब्जेक्ट के संदर्भ में पास होते हैं। यही कारण है कि गिरफ्तार तत्वों को हटाते / जोड़ते समय दोनों सरणियों के मूल्य बदल रहे हैं।

अपवाद:

arrCopy[1] = 'adding new value this way will unreference';

जब आप वैरिएबल को एक नया मान देते हैं, तो आप संदर्भ को ही बदल रहे हैं और यह मूल ऑब्जेक्ट / एरे को प्रभावित नहीं करता है।

अधिक पढ़ें


6

जैसा कि हम जावास्क्रिप्ट सरणियों और वस्तुओं में संदर्भ से जानते हैं, लेकिन बाद में एक मूल सरणी को बदलने के बिना हम उन तरीकों की प्रतिलिपि कैसे बना सकते हैं?

इसे करने के कुछ तरीके यहां दिए गए हैं:

कल्पना कीजिए कि आपके पास यह कोड आपके पास है:

var arr = [1, 2, 3, 4, 5];

1) किसी फ़ंक्शन में सरणी के माध्यम से लूपिंग और इस तरह एक नया सरणी लौटाएं:

 function newArr(arr) {
      var i=0, res = [];
      while(i<arr.length){
       res.push(arr[i]);
        i++;
       }
   return res;
 }

2) स्लाइस विधि का उपयोग करते हुए, टुकड़ा ऐरे के स्लाइसिंग भाग के लिए है, यह आपके ऐरे के कुछ हिस्से को बिना ऑरिजिनल को छुए, स्लाइस में रख देगा, यदि एरे के आरंभ और अंत को निर्दिष्ट नहीं करता है, तो यह पूरी तरह से स्लाइस कर देगा सरणी और मूल रूप से सरणी की पूरी प्रतिलिपि बनाते हैं, इसलिए हम आसानी से कह सकते हैं:

var arr2 = arr.slice(); // make a copy of the original array

3) इसके अलावा संपर्क विधि, यह दो सरणी को मर्ज करने के लिए है, लेकिन हम सिर्फ एक सरणियों को निर्दिष्ट कर सकते हैं और फिर यह मूल रूप से नए संपर्क किए गए सरणी में मानों की एक प्रति बनाते हैं:

var arr2 = arr.concat();

4) इसके अलावा विधि को कड़ा और कठोर करें, यह अनुशंसित नहीं है, लेकिन एरे और ऑब्जेक्ट को कॉपी करने का एक आसान तरीका हो सकता है:

var arr2 = JSON.parse(JSON.stringify(arr));

5) Array.from विधि, यह व्यापक रूप से समर्थित नहीं है, उपयोग करने से पहले विभिन्न ब्राउज़रों में समर्थन की जांच करें:

const arr2 = Array.from(arr);

6) ECMA6 तरीका, पूरी तरह से समर्थित भी नहीं है, लेकिन यदि आप ट्रांसपाइल चाहते हैं तो babelJs आपकी मदद कर सकता है:

const arr2 = [...arr];

6
let a = [1,2,3];

अब आप किसी भी एक सरणी की प्रतिलिपि बनाने के लिए निम्न में से कोई एक कर सकते हैं।

let b = Array.from(a); 

या

let b = [...a];

या

let b = new Array(...a); 

या

let b = a.slice(); 

या

let b = a.map(e => e);

अब, अगर मैं एक परिवर्तन,

a.push(5); 

फिर, एक है [1,2,3,5] लेकिन b अभी भी [1,2,3] है क्योंकि इसका अलग संदर्भ है।

लेकिन मुझे लगता है, Array.from के ऊपर सभी तरीकों में बेहतर है और मुख्य रूप से एक सरणी की प्रतिलिपि बनाने के लिए।


1
कौन सा सबसे तेज है
मार्क फ़्रेम


4

मेरे विशेष मामले में मुझे यह सुनिश्चित करने की ज़रूरत थी कि सरणी बरकरार रहे इसलिए यह मेरे लिए काम करता है:

// Empty array
arr1.length = 0;
// Add items from source array to target array
for (var i = 0; i < arr2.length; i++) {
    arr1.push(arr2[i]);
}

2
एक फ़ंक्शन को कॉल करके अपने कोड में अश्लीलता न जोड़ने के लिए +1, जो बिल्कुल समान काम करता है, लेकिन कम स्पष्ट तरीके से। हुड के नीचे स्लाइस अधिक कुशल हो सकता है, लेकिन कोड पर काम करने वाले किसी को भी, यह आपकी मंशा को दर्शाता है। प्लस यह बाद में अनुकूलन करने के लिए आसान बनाता है, यदि आप (उदाहरण के लिए) जो आप कॉपी कर रहे हैं उसे फ़िल्टर करें। ध्यान दें कि यह गहरी नकल को संभालता नहीं है, और समान आंतरिक वस्तुओं को संदर्भ द्वारा नए सरणी में भेजा जाता है। यह वही हो सकता है जो आप करना चाहते हैं, यह नहीं हो सकता है।
अप्रकाशित

4

बहुआयामी सरणी / ऑब्जेक्ट की प्रतिलिपि बनाएँ:

function deepCopy(obj) {
   if (Object.prototype.toString.call(obj) === '[object Array]') {
      var out = [], i = 0, len = obj.length;
      for ( ; i < len; i++ ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   if (typeof obj === 'object') {
      var out = {}, i;
      for ( i in obj ) {
         out[i] = arguments.callee(obj[i]);
      }
      return out;
   }
   return obj;
}

इस समारोह के लिए जेम्स पैडोल्सी को धन्यवाद।

स्रोत: यहाँ


3

दान, फैंसी चाल का उपयोग करने की कोई जरूरत नहीं है। बस आपको ऐसा करके arr1 की कॉपी बनानी होगी।

var arr2 = new Array(arr1);

अब arr1और arr2दो अलग-अलग सरणी चर अलग-अलग ढेर में संग्रहीत हैं। इसे jsfiddle पर देखें


यह सरणी की प्रतिलिपि नहीं करता है। यह एक तत्व के साथ एक सरणी बनाता है जो मूल (यानी var arr2 = [arr1];) का संदर्भ देता है ।
तीमुथियुस 3

3

जब हम असाइनमेंट ऑपरेटर ( =) का उपयोग करके किसी सरणी को कॉपी करना चाहते हैं, तो यह कॉपी नहीं बनाता है यह केवल सूचक / संदर्भ को कॉपी करता है। उदाहरण के लिए:

const oldArr = [1,2,3];

const newArr = oldArr;  // now oldArr points to the same place in memory 

console.log(oldArr === newArr);  // Points to the same place in memory thus is true

const copy = [1,2,3];

console.log(copy === newArr);  // Doesn't point to the same place in memory and thus is false

अक्सर जब हम डेटा ट्रांसफॉर्म करते हैं तो हम अपने शुरुआती डेटस्ट्रक्चर (जैसे एरे) को बरकरार रखना चाहते हैं। हम अपने सरणी की एक सटीक प्रतिलिपि बनाकर ऐसा करते हैं ताकि यह एक रूपांतरित हो सके, जबकि प्रारंभिक एक बरकरार रहे।

किसी सरणी की प्रतिलिपि बनाने के तरीके:

const oldArr = [1,2,3];

// Uses the spread operator to spread out old values into the new array literal
const newArr1 = [...oldArr];

// Slice with no arguments returns the newly copied Array
const newArr2 = oldArr.slice();

// Map applies the callback to every element in the array and returns a new array
const newArr3 = oldArr.map((el) => el);

// Concat is used to merge arrays and returns a new array. Concat with no args copies an array
const newArr4 = oldArr.concat();

// Object.assign can be used to transfer all the properties into a new array literal
const newArr5 = Object.assign([], oldArr);

// Creating via the Array constructor using the new keyword
const newArr6 = new Array(...oldArr);

// For loop
function clone(base) {
	const newArray = [];
    for(let i= 0; i < base.length; i++) {
	    newArray[i] = base[i];
	}
	return newArray;
}

const newArr7 = clone(oldArr);

console.log(newArr1, newArr2, newArr3, newArr4, newArr5, newArr6, newArr7);

एरे या वस्तुओं के घोंसले होने पर सावधान रहें !:

जब सरणियों को नेस्ट किया जाता है तो मानों को संदर्भ द्वारा कॉपी किया जाता है। यहाँ एक उदाहरण है कि यह कैसे मुद्दों को जन्म दे सकता है:

let arr1 = [1,2,[1,2,3]]

let arr2 = [...arr1];

arr2[2][0] = 5;  // we change arr2

console.log(arr1);  // arr1 is also changed because the array inside arr1 was copied by reference

इसलिए इन तरीकों का उपयोग न करें जब आपके सरणी के अंदर कोई ऑब्जेक्ट या सरणियाँ हों जिन्हें आप कॉपी करना चाहते हैं। यानी इन तरीकों का उपयोग केवल आदिम के सरणियों पर करें।

यदि आप इस तरह JSON.parseके साथ संयोजन के रूप में एक जावास्क्रिप्ट सरणी का उपयोग करना चाहते हैं JSON.stringify:

let arr1 = [1,2,[1,2,3]]

let arr2 = JSON.parse(JSON.stringify(arr1)) ;

arr2[2][0] = 5;

console.log(arr1);  // now I'm not modified because I'm a deep clone

नकल का प्रदर्शन:

तो हम इष्टतम प्रदर्शन के लिए किसे चुनते हैं। यह पता चला है कि सबसे क्रिया विधि, forलूप का प्रदर्शन सबसे अधिक है। forवास्तव में सीपीयू गहन प्रतिलिपि (बड़े / कई सरणियों) के लिए लूप का उपयोग करें ।

उसके बाद .slice()विधि का भी अच्छा प्रदर्शन होता है और प्रोग्रामर के लिए इसे लागू करना भी कम क्रिया और आसान होता है। मेरा सुझाव है कि .slice()आप प्रतिदिन एरियर्स की नकल के लिए उपयोग करें जो बहुत सीपीयू इंटेंसिव नहीं हैं। JSON.parse(JSON.stringify(arr))यदि कोई गहरी क्लोन की आवश्यकता नहीं है, तो (ओवरहेड के बहुत से) उपयोग करने से बचें और प्रदर्शन एक मुद्दा है।

स्रोत प्रदर्शन परीक्षण


3

यदि आपके सरणी में आदिम डेटा प्रकार के तत्व जैसे कि int, char, या string इत्यादि हैं, तो आप उन तरीकों में से किसी एक का उपयोग कर सकते हैं, जो मूल सरणी की एक प्रति लौटाता है जैसे कि .slice () या .map () या प्रसार ऑपरेटर। ES6 के लिए धन्यवाद)।

new_array = old_array.slice()

या

new_array = old_array.map((elem) => elem)

या

const new_array = new Array(...old_array);

लेकिन अगर आपके सरणी में जटिल तत्व जैसे ऑब्जेक्ट्स (या सरणियाँ) या अधिक नेस्टेड ऑब्जेक्ट हैं , तो, आपको यह सुनिश्चित करना होगा कि आप शीर्ष स्तर से अंतिम स्तर तक सभी तत्वों की एक प्रतिलिपि बना रहे हैं आंतरिक का संदर्भ वस्तुओं का उपयोग किया जाएगा और इसका मतलब है कि new_array में object_elements में बदलते मूल्य अभी भी old_array को प्रभावित करेंगे। आप प्रत्येक स्तर पर नकल करने के इस तरीके को पुराने_रूप की DEEP COPY कह सकते हैं।

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

var new_array = JSON.parse(JSON.stringify(old_array));

वहाँ कई अन्य तरीके हैं जो आप अपनी आवश्यकताओं के आधार पर उपयोग कर सकते हैं। मैंने उनमें से कुछ का उल्लेख करने के सामान्य विवरण देने के लिए केवल एक का उल्लेख किया है जब हम एक सरणी को दूसरे द्वारा मान में कॉपी करने की कोशिश करते हैं ।


बहुत बहुत धन्यवाद, आपका जवाब केवल एक ही था जिसने मेरे परिदृश्य के लिए काम किया,
अल्बर्ट श

2

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

var arr1 = ['a','b','c'];
var arr2 = [];

for (var i=0; i < arr1.length; i++) {
   arr2[i] = arr1[i];
}

आप Google पर अपरिवर्तनीय आदिम मूल्यों और परिवर्तनशील वस्तु संदर्भों के बारे में अधिक जानकारी खोज सकते हैं।


1
आपको सरणी की वस्तुओं के गुणों को स्पष्ट रूप से कॉपी करने की आवश्यकता नहीं है। देखिए चिट्टी मालेक का जवाब।
मैग्ने


2

Array को कॉपी करने के लिए आप ES6 स्प्रेड ऑपरेटर का भी उपयोग कर सकते हैं

var arr=[2,3,4,5];
var copyArr=[...arr];



2

त्वरित उदाहरण:

  1. यदि सरणी में तत्व आदिम प्रकार (स्ट्रिंग, संख्या, आदि) हैं

var arr1 = ['a','b','c'];
// arr1 and arr2 are independent and primitive elements are stored in 
// different places in the memory
var arr2 = arr1.slice(); 
arr2.push('d');
console.log(arr1); // [ 'a', 'b', 'c' ]
console.log(arr2); // [ 'a', 'b', 'c', 'd' ]

  1. यदि सरणी में तत्व वस्तु शाब्दिक हैं, तो दूसरा सरणी ({}, [])

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
// arr1 and arr2 are independent and reference's/addresses are stored in different
// places in the memory. But those reference's/addresses points to some common place
// in the memory.
var arr2 = arr1.slice(); 
arr2.pop();      // OK - don't affect arr1 bcos only the address in the arr2 is
                 // deleted not the data pointed by that address
arr2[0].x = 'z'; // not OK - affect arr1 bcos changes made in the common area 
                 // pointed by the addresses in both arr1 and arr2
arr2[1][0] = 9;	 // not OK - same above reason

console.log(arr1); // [ { x: 'z', y: 'b' }, [ 9, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]

  1. 2 के लिए समाधान : तत्व द्वारा तत्व की गहरी प्रतिलिपि

var arr1 = [{ x: 'a', y: 'b'}, [1, 2], [3, 4]];
arr2 = JSON.parse(JSON.stringify(arr1));
arr2.pop();	  // OK - don't affect arr1
arr2[0].x = 'z';  // OK - don't affect arr1
arr2[1][0] = 9;	  // OK - don't affect arr1

console.log(arr1); // [ { x: 'a', y: 'b' }, [ 1, 2 ], [ 3, 4 ] ]
console.log(arr2); // [ { x: 'z', y: 'b' }, [ 9, 2 ] ]


1

यहाँ एक प्रकार है:

var arr1=['a', 'b', 'c'];
var arr2=eval(arr1.toSource());
arr2.push('d');
console.log('arr1: '+arr1+'\narr2: '+arr2);
/*
 *  arr1: a,b,c
 *  arr2: a,b,c,d
 */

ऐसा कोई बुरा विचार नहीं है, हालाँकि मैं बेहतर तरीके से JSON स्ट्रिंग / पार्स का उपयोग करना चाहूँगा, और फिर भी एक और jsPerf तुलना करना अच्छा होगा, यह भी ध्यान रखें toSourceकि यह मानक नहीं है और उदाहरण के लिए Chrome में काम नहीं करेगा।
dmi3y

1

वहाँ नया शुरू किया गया है Array.from, लेकिन दुर्भाग्य से, इस लेखन के समय के रूप में यह हाल ही में फ़ायरफ़ॉक्स संस्करणों (32 और उच्चतर) पर समर्थित है। इसका उपयोग केवल इस प्रकार किया जा सकता है:

var arr1 = [1, 2, 3];
console.log(Array.from(arr1)); // Logs: [1, 2, 3]

संदर्भ: यहाँ

या Array.prototype.mapएक पहचान समारोह के साथ इस्तेमाल किया जा सकता है:

function identity(param)
{
    return param;
}

var arr1 = [1, 2, 3],
    clone = arr1.map(identity);

संदर्भ: यहाँ


उल्लेख के लिए +1 Array.from, जो अब इंटरनेट एक्सप्लोरर ( स्रोत ) को छोड़कर सभी प्रमुख ब्राउज़रों पर समर्थित है । ।
mgthomas99

जागरूक रहें Array.fromडेटा को म्यूट करेंगे, गहरी प्रतिलिपि / गहरी क्लोनिंग प्रदान नहीं करते हैं।
सुधांशु चौधरी

1

ES6 सरणी वाले ऑब्जेक्ट के लिए

cloneArray(arr) {
    return arr.map(x => ({ ...x }));
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.