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


83

मैंने निम्नलिखित जावास्क्रिप्ट लिखा है:

var myArray = ['a', 'b', 'c'];
var copyOfMyArray = myArray;
copyOfMyArray.splice(0, 1);
alert(myArray); // alerts ['b','c']
alert(copyOfMyArray); // alerts ['b','c']

var myNumber = 5;
var copyOfMyNumber = myNumber;
copyOfMyNumber = copyOfMyNumber - 1;
alert(myNumber); // alerts 5
alert(copyOfMyNumber); // alerts 4        

यह कोड एक चर घोषित करता है myArrayऔर इसे एक सरणी मान पर सेट करता है। यह तब एक दूसरे चर की घोषणा करता है copyOfMyArrayऔर इसे सेट करता है myArray। यह एक ऑपरेशन करता है copyOfMyArrayऔर फिर दोनों को अलर्ट करता है myArrayऔर copyOfMyArray। किसी तरह, जब मैं एक ऑपरेशन करता हूं, तो copyOfMyArrayऐसा लगता है कि उसी ऑपरेशन को किया जाता है myArray।

कोड तब एक संख्या मान के साथ एक ही काम करता है: यह एक चर घोषित करता है myNumberऔर इसे एक संख्या मान पर सेट करता है। यह तब एक दूसरे चर की घोषणा करता है copyOfMyNumberऔर इसे सेट करता है myNumber। यह एक ऑपरेशन करता है copyOfMyNumberऔर फिर दोनों को अलर्ट करता है myNumberऔर copyOfMyNumber। यहां, मुझे अपेक्षित व्यवहार मिलता है: के लिए अलग-अलग मूल्य myNumberऔर copyOfMyNumber।

एक सरणी और जावास्क्रिप्ट में एक संख्या के बीच का अंतर क्या है कि ऐसा लगता है कि एक सरणी बदलने से सरणी की एक प्रति का मूल्य बदल जाता है, जहां एक संख्या को बदलने से संख्या की प्रतिलिपि का मूल्य नहीं बदलता है?

मैं अनुमान लगा रहा हूं कि किसी कारण से, सरणी को संदर्भ और संख्या द्वारा मान से संदर्भित किया जाता है, लेकिन क्यों? मैं कैसे जान सकता हूं कि अन्य वस्तुओं के साथ क्या व्यवहार करना है?

जवाबों:


112

जावास्क्रिप्ट में एक सरणी भी एक वस्तु है और चर केवल एक वस्तु के संदर्भ को धारण करते हैं , वस्तु को नहीं। इस प्रकार दोनों चर में एक ही वस्तु का संदर्भ होता है ।

संख्या उदाहरण के साथ आपकी तुलना सही नहीं है btw। आप एक नया मान निर्दिष्ट करते हैं copyOfMyNumber। यदि आप एक नया मान निर्दिष्ट करते copyOfMyArrayहैं myArrayतो यह भी नहीं बदलेगा ।

आप slice [डॉक्स] का उपयोग करके एक सरणी की एक प्रति बना सकते हैं :

var copyOfMyArray = myArray.slice(0);

लेकिन ध्यान दें कि यह केवल एक उथली प्रतिलिपि देता है , अर्थात सरणी के अंदर की वस्तुओं का क्लोन नहीं किया जाएगा।


+1 - सिर्फ जिज्ञासा से बाहर, क्या myArray.slice(0);उस संदर्भ में सीधे असाइन करने से कोई कमी है ?
— जूली

2
@Rice: नहीं, मैं सिर्फ स्पष्ट करने के लिए संपादित करता हूं। यदि आप एक गहरी प्रतिलिपि चाहते हैं, तो आपको अपने दम पर कुछ लिखना होगा। लेकिन मुझे यकीन है कि आपको एक स्क्रिप्ट मिलेगी जो ऐसा करती है।
— फेलिक्स क्लिंग

@ फेलिक्सलिंग: मेरे पास उदाहरण नहीं है। मैं सिर्फ इसलिए पूछ रहा था क्योंकि आपने पहले प्रोटोटाइप पद्धति लागू की थी।
— जॉन्डी

@jAndy: आह तो आपने इसका उल्लेख किया है ... मैं अभी थोड़ा उलझन में था और मैं अभी हाल ही में अन्य तरीके से;)
— फेलिक्स क्लिंग

23

खैर, एकमात्र संभावित उत्तर - और सही एक - यह है कि आप वास्तव में सरणी की प्रतिलिपि नहीं बना रहे हैं । जब आप लिखते हैं

var copyOfArray = array;

आप उसी चर के संदर्भ को दूसरे चर में निर्दिष्ट कर रहे हैं । वे दोनों एक ही वस्तु पर, दूसरे शब्दों में इंगित कर रहे हैं।


मैं कहूंगा कि आप बिल्कुल संदर्भ सूचक निर्दिष्ट नहीं कर रहे हैं, आप संदर्भ की प्रति की तरह असाइन कर रहे हैं। चूंकि यदि आप कार्य करने के लिए obj पास करते हैं और इसे फ़ंक्शन के अंदर किसी अन्य नए ऑब्जेक्ट के साथ बदलने का प्रयास करते हैं, तो आप मूल ऑब्जेक्ट को नहीं बदलेंगे।
— काश्नरैंड

1
@kashesandr हाँ, "एक संदर्भ निर्दिष्ट करना" का अर्थ है "संदर्भ की एक प्रति प्रदान करना", यह सच है। हालांकि दो समान संदर्भ हमेशा समान होते हैं, जैसे संख्या के दो उदाहरण 5हमेशा समान होते हैं।
— पॉइन्टी

16

तो यहाँ हर किसी ने यह समझाने का एक बड़ा काम किया है कि ऐसा क्यों हो रहा है - मैं सिर्फ एक लाइन छोड़ना चाहता था और आपको बता दूं कि मैं इसे कैसे ठीक कर सकता था - बहुत आसानी से:

thingArray = ['first_thing', 'second_thing', 'third_thing']
function removeFirstThingAndPreserveArray(){
  var copyOfThingArray = [...thingArray]
  copyOfThingArray.shift();
  return copyOfThingArray;
}

यह ... प्रसार सिंटैक्स का उपयोग कर रहा है।

फैला हुआ सिंटैक्स स्रोत

संपादित करें: इस के कारण , और अपने प्रश्न का उत्तर देने के लिए:

एक सरणी और जावास्क्रिप्ट में एक संख्या के बीच का अंतर क्या है कि ऐसा लगता है कि एक सरणी बदलने से सरणी की एक प्रति का मूल्य बदल जाता है, जहां एक संख्या को बदलने से संख्या की प्रतिलिपि का मूल्य नहीं बदलता है?

इसका उत्तर है कि जावास्क्रिप्ट में, सरणियाँ और वस्तुएं परस्पर परिवर्तनशील हैं , जबकि तार और संख्याएँ और अन्य प्राइमिटिव अपरिवर्तनीय हैं । जब हम एक कार्य करते हैं जैसे:

var myArray = ['a', 'b', 'c']; var copyOfMyArray = myArray;

copyOfMyArray वास्तव में myArray का केवल एक संदर्भ है, वास्तविक प्रति नहीं।

मैं इस लेख की सिफारिश करूंगा, क्या अपरिवर्तनीय और परिवर्तनशील डेटा संरचनाएं हैं? , विषय में गहराई से खुदाई करने के लिए।

एमडीएन शब्दावली: म्यूटेबल


2
ठीक वही जो मेरे द्वारा खोजा जा रहा था।
— फेबियन थिसलिंग

6

क्लोनिंग ऑब्जेक्ट्स -

A के loop / array.pushसमान परिणाम उत्पन्न करता है array.slice(0)या array.clone()। मान सभी संदर्भ द्वारा पारित किए जाते हैं, लेकिन चूंकि अधिकांश आदिम डेटा प्रकार अपरिवर्तनीय हैं , बाद के संचालन वांछित परिणाम उत्पन्न करते हैं - एक 'क्लोन'। यह वस्तुओं और सरणियों का सच नहीं है, ज़ाहिर है, जो मूल संदर्भ के संशोधन की अनुमति देते हैं (वे परस्पर प्रकार हैं)।

निम्नलिखित उदाहरण लें:

const originalArray = [1, 'a', false, {foor: 'bar'}]
const newArray = [];

originalArray.forEach((v, i) => {
    newArray.push(originalArray[i]);
});

newArray[0] = newArray[0] + 1;
newArray[1] = 'b';
newArray[2] = true;
newArray[3] = Object.assign(newArray[3], {bar: 'foo'});

NewArray पर चलाए जाने वाले संचालन, अंतिम (ऑब्जेक्ट) को छोड़कर, सभी वांछित परिणाम उत्पन्न करते हैं, जो कि, क्योंकि यह संदर्भ द्वारा कॉपी किया गया है, साथ ही साथ ऑरिज मूल [3] को म्यूट कर देगा।

https://jsfiddle.net/7ajz2m6w/

ध्यान दें कि array.slice(0) and array.clone()इसी सीमा से ग्रस्त है।

इसे हल करने का एक तरीका पुश सीक्वेंस के दौरान ऑब्जेक्ट को प्रभावी ढंग से क्लोन करना है:

originalArray.forEach((v, i) => {
    const val = (typeof v === 'object') ? Object.assign({}, v) : v;
    newArray.push(val);
});

https://jsfiddle.net/e5hmnjp0/

चियर्स


3

जेएस में, ऑपरेटर "=" सूचक को सरणी के मेमोरी क्षेत्र में कॉपी करता है। यदि आप किसी सरणी को दूसरे में कॉपी करना चाहते हैं तो आपको क्लोन फ़ंक्शन का उपयोग करना होगा।

पूर्णांकों के लिए अलग है क्योंकि वे एक आदिम प्रकार हैं।

एस


1

आदिम डेटा प्रकारों (स्ट्रिंग्स और संख्या IIRC) को छोड़कर सबकुछ संदर्भ द्वारा कॉपी किया जाता है।


यह सच नहीं है। सभी असाइनमेंट संदर्भ निर्दिष्ट करते हैं। तार और संख्या अपरिवर्तनीय हैं।
— SLAKs

1

आपकी कोई प्रति नहीं है।
आपके पास एक ही सरणी रखने वाले कई चर हैं।

इसी तरह, आपके पास एक ही नंबर रखने वाले कई वैरिएबल हैं।

जब आप लिखते हैं copyOfMyNumber = ..., तो आप चर में एक नया नंबर डाल रहे होते हैं।
वह लिखने जैसा है copyOfMyArray = ...।

जब आप लिखते हैं copyOfMyArray.splice, तो आप मूल सरणी को संशोधित कर रहे हैं ।
यह संख्याओं के साथ संभव नहीं है क्योंकि संख्याएं अपरिवर्तनीय हैं और इन्हें संशोधित नहीं किया जा सकता है,


1

सरणी में मूल सरणी का एक फ़िल्टर बनाएँ। ताकि नए सरणी में परिवर्तन मूल सरणी को प्रभावित न करें।

var myArray = ['a', 'b', 'c'];
var arrayCopy = myArray.filter(function(f){return f;})
arrayCopy.splice(0, 1);
alert(myArray); // alerts ['a','b','c']
alert(arrayCopy); // alerts ['b','c']

आशा है कि इससे सहायता मिलेगी।


1

उथली प्रतिलिपि के साथ मुद्दा यह है कि सभी ऑब्जेक्ट क्लोन नहीं किए जाते हैं, इसके बजाय इसे संदर्भ मिलता है। क्योंकि array.slice (0) केवल शाब्दिक सरणी के साथ ठीक काम करेगा, लेकिन यह ऑब्जेक्ट सरणी के साथ उथले प्रतिलिपि नहीं करेगा। उस मामले में एक तरीका है ..

var firstArray = [{name: 'foo', id: 121}, {name: 'zoo', id: 321}];
var clonedArray = firstArray.map((_arrayElement) => Object.assign({}, _arrayElement));  
console.log(clonedArray);
// [{name: 'foo', id: 121}, {name: 'zoo', id: 321}]  // shallow copy

0

आप अपने मामलों के आधार पर कुछ त्रुटि से निपटने को जोड़ सकते हैं और समस्या को हल करने के लिए निम्न फ़ंक्शन के समान कुछ का उपयोग कर सकते हैं। कृपया किसी भी कीड़े / मुद्दों / दक्षता विचारों के लिए टिप्पणी करें।

function CopyAnArray (ari1) {
   var mxx4 = [];
   for (var i=0;i<ari1.length;i++) {
      var nads2 = [];
      for (var j=0;j<ari1[0].length;j++) {
         nads2.push(ari1[i][j]);
      }
      mxx4.push(nads2);
   }
   return mxx4;
}

-1

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

http://plnkr.co/edit/Bqvsiddke27w9nLwYhcl?p=preview

// for showing that objects in javascript shares the same reference

var obj = {
  "name": "a"
}

var arr = [];

//we push the same object
arr.push(obj);
arr.push(obj);

//if we change the value for one object
arr[0].name = "b";

//the other object also changes
alert(arr[1].name);

ऑब्जेक्ट क्लोन के लिए, हम jquery और angular.copy () में .clone () का उपयोग कर सकते हैं, ये फ़ंक्शन अन्य संदर्भ के साथ नई ऑब्जेक्ट बनाएंगे। यदि आप ऐसा करने के लिए अधिक कार्य जानते हैं, तो कृपया मुझे बताएं, धन्यवाद!

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