[Javascript] 배열(참조형 변수) 복사

Haksoo JI·2022년 11월 4일
0

[Javascript] 배열 복사

프로그래머스에서 Javascript 코딩테스트 연습문제를 풀던 중에 배열을 복사해야 할 일이 생겼다. sort() 메서드를 사용해서 요소의 index들을 다른 순서로 정렬하고 싶었는데 원래의 배열 순서도 보존해야 했기 때문이다. 메서드가 기존 배열의 순서를 변형시키다보니 기존의 순서로 배열의 요소들을 불러올 수 없었다. 그래서 평소에 변수를 복사하는 것처럼 똑같이 시도했다. 다음과 같이 말이다.

const originArray = [123, 55, 90, 7, 1000, 40]
let saved = originArray;
let sorted = originArray.sort((a,b) => a - b)

그 후 기존 배열을 사용하려고 saved 를 호출했는데, 뭔가 이상해서 console.log로 찍어보니 변한 상태였다.

> console.log(saved)
  (6) [7, 40, 55, 90, 123, 1000]

무엇이 문제인가 싶어서 배열이 아닌 변수로는 잘 되는지 확인해보았다.

let origin = '나는문자열'
let saved = origin
origin = 'changed'
console.log(saved) // 출력: 나는문자열

변수는 복사가 잘만 된다.
왜 배열에서는 복사가 되지않는 것일까? 그리고 가장 처음 코드를 보면 상수를 선언할 때 사용하는 예약어인 const로 선언했는데도 했는데도 배열이 수정이 가능하며 오류메시지가 나타나지 않는다. 배열이 아니라 값을 저장하는 변수에서는 오류메시지가 나오는데 말이다.

이유는 배열을 변수에 저장하게 되면 변수는 배열의 값을 저장하는 것이 아니라 배열이 저장되어 있는 데이터 공간의 주소를 저장하게 된다. 이를 참조형 변수라고 한다. 객체도 마찬가지다.

배열이 아닌 값을 변수에 저장하는 경우를 먼저 살펴보자. '나는문자열'이라는 문자열이 값으로 저장된 변수 origin을 변수 saved에 저장했다. 이 경우에는 두 변수에는 각각 '나는 문자열'이라는 값이 저장된다. 따라서 각기 수정하거나 삭제해도 다른 주소를 가진 저장공간에 문자열이 저장되어 있기 때문에 서로 영향을 끼치지 않는다.

그러나 배열이나 객체 같은 참조형 변수는 다르다. 맨 위의 배열을 복사하는 코드를 살펴보면 originArray[123, 55, 90, 7, 1000, 40] 배열을 할당할 때, 변수에는 값이 아니라 배열이 저장된 공간의 주소가 입력되는 것이다. 변수를 호출하면 변수는 저장된 주소를 통해 배열이 저장된 저장 공간을 찾아가서 배열을 불러온다. 따라서 복사를 위해 다른 변수 saved에 기존 변수를 할당하게 되면 두 변수는 모두 같은 주소를 가리키게 된다. 따라서 하나의 변수를 호출해서 해당 저장 공간에 있는 배열을 수정하거나 하면 다른 변수를 호출했을 때에도 영향을 끼치게 되는 것이다.

예를 들자면 집주소와 같다고 볼 수 있다. 친구 '빵빵이'가 A라는 주소에 살고 있다고 생각해보자. 우리는 머릿속에 '빵빵이'라는 친구를 찾아가기 위해서 주소 A를 불러올 것이다. 그런데 만약 빵빵이가 이사를 가고 쭈글이가 그 집에 들어와서 살게 될 수도 있다. 그렇게 되면 우리는 머릿속에 같은 주소 A를 떠올리겠지만 A라는 공간 안에는 다른 사람이 살고 있는 것이다.

복사하는 방법은?

그러면 이러한 참조형 변수를 복사하고 싶으면 어떻게 할까?
각 요소들이 모두 값이라면, 요소들을 따로 불러와서 하나씩 복사하고자 하는 배열에 집어넣으면 될 것이다. 이런 방식을 얕은 복사하고 한다. 여러가지 매서드를 활용해서 복사할 수 있다.

그런데 얕은 복사라고 부르는 이유는 깊게 복사해야 하는 경우가 있기 때문이다. 예를 들어 배열 안에 배열이 있다면, 요소 자체가 여전히 값이 아니라 주소이기 때문에 온전한 복사가 되지 않는다. 그 주소를 참조하는 다른 변수에서 배열의 데이터를 수정하면 여전히 영향을 받기 때문이다.

가장 확실하게 객체나 중첩배열이나 다차원배열을 복사하기 위해서는 깊은 복사를 사용해야 한다. 깊은 복사는 다음과 같이 JSON 메서드를 활용해서 할 수 있다.

let A = [[1, 2], 3, ['a', 'b', 'c'], 'd'];
let B = JSON.parse(JSON.stringify(A));

JSON.stringfy(자료): '자료'를 JSON으로 변환
JSON.parse(JSON 문자열): 'JSON 문자열'을 자바스크립트 객체로 전개


참조 :
https://developer-talk.tistory.com/325
https://ko.javascript.info/object-copy

profile
아직 씨앗입니다. 무슨 나무가 될까요?

0개의 댓글