
먼저 배열을 복사하는 방법을 알기 전에 배열이 어떤 원리로 복사되는지부터 알면 더 좋다.
따라서 만약 원시타입과 객체 타입을 잘 모른다면 간단하게 정리된 아래 글을 읽고 오면 좋다.
[JS - 개념] 원시타입(Primitive Type)과 객체 타입(Object/Reference Type)
원시 타입 ( Primitive Type ) 원시 타입에 속하는 데이터 타입에는 아래와 같이 6가지가 존재한다. Number & Bigint String Boolean null unjdefined Symbol 객체 타입은 원시 타입을 제외한 나머지 객체 타입(참조)
html-jc.tistory.com
배열 복사하는 방법은 여러가지가 있다.
그중 여러분이 생각하는 가장 쉬운 방법은 아래와 같다.
// 1번 문제
let arrA = [7,8,9];
let arrB = arrA;
arrB[0] = 10;
console.log(arrA); // [10, 8, 9]
console.log(arrB); // [10, 8, 9]
// 2번 문제
let arrA = [7, 8, 9];
let arrB = arrA;
arrB = [11, 12, 13];
console.log(arrA); // [ 7, 8, 9 ]
console.log(arrB); // [ 11, 12, 13 ]
arrB[0] = 99;
console.log(arrA); //?
console.log(arrB); //?
1번 문제와 2번 문제의 차이를 알야 한다.
1번 문제는 참조 값을 복사(얕은 복사)이다. 따라서 arrA와 arrB는 같은 객체 타입을 가리키고 있다. 그 결과 어느 한쪽에서 값을 변경하면 서로 영향을 주고받는다.
이렇게 되는 이유는 메모리를 효율적으로 사용하기 위해 그리고 객체타입을 복사해 생성하는 비용을 절약하여 성능을 향상하기 위해 객체타팁은 변경 가능한 값으로 설계되었기 때문이다.
따라서 객체 타입의 변수들은 데이터 복사가 일어날 때 원시 타입의 복사처럼 값이 담긴 주솟값을 바로 복사하지 않고, 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복사한다. 이는 "참조에 의한 전달" 즉 "얕은 복사"라고도 한다.
반면에 2번은 처음에는 앝은복사를 했지만 그다음에 arrB = [11, 12, 13]이라는 새로운 객체 타입을 할당해 주게 되면서 메모리 데이터 영역의 새 공간에 새로운 객체 타입이 저장되었고 그 주소를 변수 영역의 arrB에 저장하게 된다.
따라서 arrA와 arrB가 다른 객체타입을 가리키게 되므로 arrA가 가리키는 값은 arrB에서 값을 변경해도 달라지지 않는다.
- 얕은 복사
- slice()
- spread 연사자
- concat()
- map() 함수
- filter()
- reduce()
- from()
- 깊은 복사
- JSON.parse()함수
- JSON.stringify()함수
slice()
let arr = [ 1, 2, 3, 4];
let copy = arr.slice();
copy[0] = 10
console.log(arr); // [ 1, 2, 3, 4 ]
console.log(copy);// [ 10, 2, 3, 4 ]
여기서 의문점을 가진 사람들이 있을 수 있다. 얕은 복사인데 원본 배열이 바뀌지 않았네요? 네 바뀌지 않습니다.
MDN 문서에서 slice를 찾아보면
'slice 메서드는 어떤 배열의 begin부터 end(end 미포함)까지에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다.
원본 배열은 바뀌지 않습니다.' 라고 되어있습니다. 여기서 중요한 것은 "새로운 배열 객체로 반환"한다입니다.
아까 위에서와 같이 새로운 객체타입을 할당해 주게 되면 메모리 데이터 영역의 새 공간에 새로운 객체타입이 저장되었고 그 주소를 변수 영역의 copy에 저장한 것입니다.
따라서 copy와 연결되어있는 객체 타입의 값을 변경해도 arr의 값이 변경되지 않는 것입니다.
이처럼 우리는 원본배열이 변경되지 않으면서 복사하기 위해서는 이렇게 새로운 배열 객체를 반환하는 형태의 메서드를 사용하면 됩니다.
spread 연산자
let arr = [1, 2, 3];
let copy = [...arrA];
copy[0] = 10;
console.log(arr);
// [1, 2, 3]
console.log(copy);
// [10, 2, 3]
concat()
let arr = [1, 2, 3];
let copy = arr.concat();
copy[0] = 10;
console.log(arr);
// [1, 2, 3]
console.log(copy);
// [10, 2, 3]
map(), filter(), reduce(), from()
위 모든 함수는 기존의 배열로 얕은 복사후 그것으로 새로운 배열 객체로 반환합니다. (위에 concat(), slice() 도 당연히 포함)
그렇기에 여기있는 함수를 사용해도 원본배열이 바뀌지 않습니다.
JSON.parse() 함수 및 JSON.stringify()함수
이 함수들은 지금까지 설명했던 함수들과 달리 다차원 배열을 정상적으로 복사할 수 있습니다.
JSON.stringify() 함수로 원본 배열을 문자열로 변환 후 JSON.parse() 함수로 JavaScript Object로 파싱 합니다.
let arr = [[1, 2, 3,], ['A', 'B', 'C']];
let copy = JSON.parse(JSON.stringify(arrA));
copy[0][0] = 10;
console.log(arr); // [[1, 2, 3], ['A', 'B', 'C']]
console.log(copy); // [[10, 2, 3], ['A', 'B', 'C']]
'Javascript > 개념' 카테고리의 다른 글
[JS - 개념] 원시타입(Primitive Type)과 객체 타입(Object/Reference Type) (1) | 2023.11.12 |
---|---|
[JS - 개념] 재귀함수와 증감연산자를 사용할 때 주의점 (1) | 2023.10.15 |
[JS - 놓치기 쉬운 개념] parseInt() 개념 및 주의할 점들 (0) | 2023.09.05 |
[JS - 개념] Sort() <배열 고차함수> (0) | 2023.05.26 |
[JS - 개념] String.prototype.replace() (0) | 2023.01.31 |

먼저 배열을 복사하는 방법을 알기 전에 배열이 어떤 원리로 복사되는지부터 알면 더 좋다.
따라서 만약 원시타입과 객체 타입을 잘 모른다면 간단하게 정리된 아래 글을 읽고 오면 좋다.
[JS - 개념] 원시타입(Primitive Type)과 객체 타입(Object/Reference Type)
원시 타입 ( Primitive Type ) 원시 타입에 속하는 데이터 타입에는 아래와 같이 6가지가 존재한다. Number & Bigint String Boolean null unjdefined Symbol 객체 타입은 원시 타입을 제외한 나머지 객체 타입(참조)
html-jc.tistory.com
배열 복사하는 방법은 여러가지가 있다.
그중 여러분이 생각하는 가장 쉬운 방법은 아래와 같다.
// 1번 문제 let arrA = [7,8,9]; let arrB = arrA; arrB[0] = 10; console.log(arrA); // [10, 8, 9] console.log(arrB); // [10, 8, 9]
// 2번 문제 let arrA = [7, 8, 9]; let arrB = arrA; arrB = [11, 12, 13]; console.log(arrA); // [ 7, 8, 9 ] console.log(arrB); // [ 11, 12, 13 ] arrB[0] = 99; console.log(arrA); //? console.log(arrB); //?
1번 문제와 2번 문제의 차이를 알야 한다.
1번 문제는 참조 값을 복사(얕은 복사)이다. 따라서 arrA와 arrB는 같은 객체 타입을 가리키고 있다. 그 결과 어느 한쪽에서 값을 변경하면 서로 영향을 주고받는다.
이렇게 되는 이유는 메모리를 효율적으로 사용하기 위해 그리고 객체타입을 복사해 생성하는 비용을 절약하여 성능을 향상하기 위해 객체타팁은 변경 가능한 값으로 설계되었기 때문이다.
따라서 객체 타입의 변수들은 데이터 복사가 일어날 때 원시 타입의 복사처럼 값이 담긴 주솟값을 바로 복사하지 않고, 값이 담긴 주솟값들로 이루어진 묶음을 가리키는 주솟값을 복사한다. 이는 "참조에 의한 전달" 즉 "얕은 복사"라고도 한다.
반면에 2번은 처음에는 앝은복사를 했지만 그다음에 arrB = [11, 12, 13]이라는 새로운 객체 타입을 할당해 주게 되면서 메모리 데이터 영역의 새 공간에 새로운 객체 타입이 저장되었고 그 주소를 변수 영역의 arrB에 저장하게 된다.
따라서 arrA와 arrB가 다른 객체타입을 가리키게 되므로 arrA가 가리키는 값은 arrB에서 값을 변경해도 달라지지 않는다.
- 얕은 복사
- slice()
- spread 연사자
- concat()
- map() 함수
- filter()
- reduce()
- from()
- 깊은 복사
- JSON.parse()함수
- JSON.stringify()함수
slice()
let arr = [ 1, 2, 3, 4]; let copy = arr.slice(); copy[0] = 10 console.log(arr); // [ 1, 2, 3, 4 ] console.log(copy);// [ 10, 2, 3, 4 ]
여기서 의문점을 가진 사람들이 있을 수 있다. 얕은 복사인데 원본 배열이 바뀌지 않았네요? 네 바뀌지 않습니다.
MDN 문서에서 slice를 찾아보면
'slice 메서드는 어떤 배열의 begin부터 end(end 미포함)까지에 대한 얕은 복사본을 새로운 배열 객체로 반환합니다.
원본 배열은 바뀌지 않습니다.' 라고 되어있습니다. 여기서 중요한 것은 "새로운 배열 객체로 반환"한다입니다.
아까 위에서와 같이 새로운 객체타입을 할당해 주게 되면 메모리 데이터 영역의 새 공간에 새로운 객체타입이 저장되었고 그 주소를 변수 영역의 copy에 저장한 것입니다.
따라서 copy와 연결되어있는 객체 타입의 값을 변경해도 arr의 값이 변경되지 않는 것입니다.
이처럼 우리는 원본배열이 변경되지 않으면서 복사하기 위해서는 이렇게 새로운 배열 객체를 반환하는 형태의 메서드를 사용하면 됩니다.
spread 연산자
let arr = [1, 2, 3]; let copy = [...arrA]; copy[0] = 10; console.log(arr); // [1, 2, 3] console.log(copy); // [10, 2, 3]
concat()
let arr = [1, 2, 3]; let copy = arr.concat(); copy[0] = 10; console.log(arr); // [1, 2, 3] console.log(copy); // [10, 2, 3]
map(), filter(), reduce(), from()
위 모든 함수는 기존의 배열로 얕은 복사후 그것으로 새로운 배열 객체로 반환합니다. (위에 concat(), slice() 도 당연히 포함)
그렇기에 여기있는 함수를 사용해도 원본배열이 바뀌지 않습니다.
JSON.parse() 함수 및 JSON.stringify()함수
이 함수들은 지금까지 설명했던 함수들과 달리 다차원 배열을 정상적으로 복사할 수 있습니다.
JSON.stringify() 함수로 원본 배열을 문자열로 변환 후 JSON.parse() 함수로 JavaScript Object로 파싱 합니다.
let arr = [[1, 2, 3,], ['A', 'B', 'C']]; let copy = JSON.parse(JSON.stringify(arrA)); copy[0][0] = 10; console.log(arr); // [[1, 2, 3], ['A', 'B', 'C']] console.log(copy); // [[10, 2, 3], ['A', 'B', 'C']]
'Javascript > 개념' 카테고리의 다른 글
[JS - 개념] 원시타입(Primitive Type)과 객체 타입(Object/Reference Type) (1) | 2023.11.12 |
---|---|
[JS - 개념] 재귀함수와 증감연산자를 사용할 때 주의점 (1) | 2023.10.15 |
[JS - 놓치기 쉬운 개념] parseInt() 개념 및 주의할 점들 (0) | 2023.09.05 |
[JS - 개념] Sort() <배열 고차함수> (0) | 2023.05.26 |
[JS - 개념] String.prototype.replace() (0) | 2023.01.31 |