JavaScript에서 배열을 변경하면 배열 복사본에 영향을 미치는 이유는 무엇입니까?


83

다음 JavaScript를 작성했습니다.

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.

배열을 변경하면 배열 사본의 값이 변경되는 것처럼 보이는 JavaScript에서 배열과 숫자의 차이점은 무엇입니까? 숫자를 변경해도 숫자 사본의 값은 변경되지 않습니까?

어떤 이유로 배열은 참조로 참조되고 숫자는 값으로 참조되지만 그 이유는 무엇입니까? 다른 개체에 대해 예상되는 동작을 어떻게 알 수 있습니까?

답변:


112

JavaScript의 배열도 객체 이며 변수 는 객체 자체가 아닌 객체에 대한 참조 만 보유 합니다. 따라서 두 변수 모두 동일한 객체에 대한 참조를 갖습니다 .

숫자 예제와의 비교가 정확하지 않습니다. 에 새 값을 할당합니다 copyOfMyNumber. 새 값을 할당 copyOfMyArray해도 변경되지 않습니다 myArray.

slice [docs]를 사용하여 배열의 복사본을 만들 수 있습니다 .

var copyOfMyArray = myArray.slice(0);

그러나 이것은 얕은 복사본 만 반환합니다 . 즉, 배열 내부의 개체는 복제되지 않습니다.


+1-그냥 호기심 때문인데, myArray.slice(0);그 맥락에서 직접 할당하면 어떤 단점이 있습니까?
jAndy

2
@Rice : 아니요, 명확히하기 위해 편집합니다. 딥 카피를 원하면 직접 작성해야합니다. 그러나 나는 당신이 이것을 수행하는 스크립트를 찾을 것이라고 확신합니다.
Felix Kling

@FelixKling : 예가 없습니다. 먼저 프로토 타입 방법을 적용했기 때문에 물어 봤습니다.
jAndy

@jAndy : 당신이 언급 그래서 아 ... 난 조금 혼란이었고, 최근에 더 자주 난 그냥 다른 방법)
펠릭스 클링

23

유일하게 가능한 대답과 정답은 실제로 어레이를 복사하지 않는다는 것입니다. 당신이 쓸 때

var copyOfArray = array;

동일한 배열에 대한 참조 를 다른 변수에 할당하고 있습니다. 즉, 둘 다 같은 물체를 가리키고 있습니다.


정확히 참조 포인터를 할당하지 않고 참조 사본처럼 할당하고 있다고 말하고 싶습니다. obj를 함수에 전달하고 함수 내에서 다른 새 개체로 바꾸려고하면 원래 개체가 변경되지 않습니다.
kashesandr

1
@kashesandr 예, "참조 할당"은 " 참조 사본 할당"을 의미 합니다. 사실입니다. 그러나 숫자의 두 인스턴스가 항상 같 듯이 두 개의 동일한 참조 5는 항상 같습니다.
Pointy

16

그래서 여기있는 모든 사람들 이 이런 일이 일어나는지 설명하는 훌륭한 일을했습니다. 저는 그저 줄을 끊고 제가 어떻게이 문제를 해결할 수 있었 는지 알려 드리고 싶었습니다 . 아주 쉽게 :

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

이것은 ... spread 구문을 사용하고 있습니다.

스프레드 구문 소스

편집 : 이것의 이유 와 귀하의 질문에 대한 답변 :

배열을 변경하면 배열 사본의 값이 변경되는 것처럼 보이는 JavaScript에서 배열과 숫자의 차이점은 무엇입니까? 숫자를 변경해도 숫자 사본의 값은 변경되지 않습니까?

대답은 JavaScript에서 배열과 객체는 변경 가능 하고 문자열과 숫자 및 기타 기본 요소는 변경할 수 없다는 것입니다 . 다음과 같은 과제를 수행 할 때 :

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

copyOfMyArray는 실제 사본이 아니라 실제로 myArray에 대한 참조 일뿐입니다.

이 기사를 추천합니다. 불변 및 변경 가능한 데이터 구조는 무엇입니까? , 주제를 더 깊이 파헤칩니다.

MDN 용어 : 변경 가능


2
내가 찾던 바로 그것.
Fabien TheSolution

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 인덱스에서 실행되는 작업은 모두 원하는 결과를 생성합니다. 단, 최종 (객체)은 참조로 복사되기 때문에 originalArray [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

JS에서 연산자 "="는 포인터를 배열의 메모리 영역에 복사합니다. 배열을 다른 배열로 복사하려면 Clone 기능을 사용해야합니다.

정수의 경우 원시 유형이기 때문에 다릅니다.

에스.


1

원시 데이터 유형 (문자열 및 숫자 IIRC)을 제외한 모든 것은 참조로 복사됩니다.


사실이 아닙니다. 모든 할당은 참조를 할당합니다. 문자열과 숫자는 변경할 수 없습니다.
SLaks

1

사본이 없습니다.
동일한 배열을 보유하는 여러 변수가 있습니다.

마찬가지로 동일한 숫자를 가진 여러 변수가 있습니다.

를 쓸 때 copyOfMyNumber = ...변수에 새 숫자를 넣는 것입니다.
그것은 쓰기와 같습니다 copyOfMyArray = ....

당신이 쓸 때 copyOfMyArray.splice, 당신은하고 원래의 배열을 수정 .
숫자는 변경할 수없고 수정할 수 없기 때문에 불가능합니다.


1

arrayCopy에 원래 배열의 필터를 만듭니다. 따라서 새 어레이에 대한 변경 사항은 원래 어레이에 영향을주지 않습니다.

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 ()을 사용할 수 있으며 이러한 함수는 다른 참조로 새 객체를 생성합니다. 더 많은 기능을 알고 있다면 감사합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.