1.깊은 복사(Deep Copy)와 얕은 복사(Shallow Copy)
ㄱ. 깊은 복사
- 객체의 모든 속성을 완전히 복사하는 것임 즉, 원본 객체와 복사된 객체가 서로 다른 메모리 공간을 차지하게 되며, 복사된 객체를 수정해도 원본 객체에는 영향을 미치지 않음.
let original = { a: 1, b: { c: 2 } };
let deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.b.c = 3;
console.log(original.b.c);
// 출력: 2
ㄴ. 얕은 복사
- 객체의 1단계 속성들만 복사하는 것임. 중첩된 객체나 배열 등은 복사되지 않고, 그 참조(레퍼런스)만 복사됨. 따라서 얕은 복사된 객체의 중첩된 객체를 수정하면 원본 객체도 영향을 받음.
let original = { a: 1, b: { c: 2 } };
let shallowCopy = { ...original };
shallowCopy.b.c = 3;
console.log(original.b.c);
// 출력: 3
2. 콜바이 벨류(Call by Value)와 콜바이 레퍼런스(Call by Reference)
ㄱ. 콜바이 벨류(Call by Value)
- 함수에 값을 전달할 때, 인수로 전달된 값이 복사되어 함수 내부에서 사용되는 방식임. 원본 값은 함수 내부에서 변경되지 않음.
let num = 10;
function modifyValue(x) {
x = 20;
}
modifyValue(num);
console.log(num); // 출력: 10
ㄴ. 콜바이 레퍼런스(Call by Reference)
- 함수에 값을 전달할 때, 인수로 전달된 값의 참조(레퍼런스)가 함수로 전달됨. 따라서 함수 내부에서 그 값을 수정하면 원본 값도 수정됨.
let obj = { a: 1 };
function modifyObject(y) {
y.a = 2;
}
modifyObject(obj);
console.log(obj.a); // 출력: 2
3. 얕은복사와 콜바이 레퍼런스
- 얕은 복사와 콜바이 레퍼런스는 비슷한 부분이 있지만, 정확히 같은 개념은 아님.
ㄱ. 얕은 복사
- 객체의 1단계 속성만 복사하는 방식임. 중첩된 객체나 배열 등은 복사되지 않고, 참조만 복사되기 때문에 원본과 복사본이 중첩된 객체나 배열을 공유하게 됨.
ㄴ. 콜바이 레퍼런스
- 함수 호출 시, 변수에 저장된 값이 아니라 그 변수의 참조(메모리 주소)가 전달되는 방식임. 함수 내부에서 그 참조를 통해 원본 데이터를 수정할 수 있음.
ㄷ. 비슷한 점
- 둘 다 참조(레퍼런스)를 통해 원본 데이터를 공유하거나 수정할 수 있다는 것임.
- 얕은 복사에서 중첩된 객체나 배열이 참조되기 때문에 원본 데이터가 변경될 수 있는 것처럼, 콜바이 레퍼런스에서도 참조를 통해 원본 데이터를 변경할 수 있음.
- 얕은 복사는 주로 객체나 배열을 복사할 때의 방법을 설명할 때 사용됨.
- 콜바이 레퍼런스는 함수 호출 시 데이터 전달 방식에 대한 설명에서 사용됨.
ㄹ. 결론
- 얕은 복사에서의 참조와 콜바이 레퍼런스에서의 참조가 비슷한 동작을 보이지만, 각각의 맥락과 목적이 다르기 때문에 같은 개념으로 보기는 어려움.
4. JS에서 콜바이 레퍼런스란
- JS에서는 기본 타입(Primitive Types)과 참조 타입(Reference Types)이 있음:
ㄱ. 기본타입
- 기본 타입: 숫자, 문자열, 불리언, null, undefined, symbol, bigint 등. 이들은 값 자체가 복사되어 함수에 전달됨. 함수 내부에서 값을 변경해도 원본 값은 변하지 않음.
let a = 10;
function modifyValue(x) {
x = 20;
}
modifyValue(a);
console.log(a); // 출력: 10
ㄴ. 참조 타입
- 객체, 배열, 함수 등. 이들은 실제 값이 아닌 참조(메모리 주소)가 복사되어 함수에 전달됨. 함수 내부에서 참조를 통해 객체의 속성을 변경하면, 원본 객체도 영향을 받음. 이 때문에 마치 콜바이 레퍼런스처럼 동작하는 것처럼 보일 수 있음.
let obj = { a: 1 };
function modifyObject(o) {
o.a = 2;
}
modifyObject(obj);
console.log(obj.a); // 출력: 2
- 여기서 중요한 점은 참조 타입의 경우에도 참조 자체는 콜바이 벨류로 전달된다는 것임. 즉, 함수에 전달된 것은 객체의 참조(주소)이며, 이 참조는 값처럼 복사되어 함수에 전달됨.
ㄷ. 결론
- 결론적으로 JS에서는 기본 타입이든 참조 타입이든 모든 인수는 콜바이 벨류로 전달됨. 참조 타입은 참조가 복사되어 전달되므로, 함수 내부에서 객체나 배열의 속성을 변경할 수 있지만, 참조 자체를 변경해도 원본에는 영향을 주지 않음. 그래서 엄밀히 말하면, JS에서는 콜바이 레퍼런스가 없음.
5. 메모리 사용
ㄱ. 예시코드
const [state, setState] = useState([]);
const parse = new ParseData();
const result = parse.data;
setState ( result.message)
ㄴ. parse.data가 객체일경우
- result에 parse.data 객체가 할당될 때, 객체의 참조값(메모리 주소)이 result에 복사됨.
- result.message가 또 다른 객체나 배열이라면, setState(result.message)를 호출할 때, result.message의 참조값이 state로 전달됨. 이 경우, state는 result.message 객체를 참조하게 됨.
- 메모리에서는 객체 자체가 복사되지 않고, 동일한 객체에 대한 참조가 state로 전달되기 때문에, 메모리 사용량은 객체 하나만 차지하는 공간과 동일함.
ㄷ. parse.data가 원시값일경우
- parse.data가 숫자, 문자열 등 원시값일 경우, result에는 그 값 자체가 복사됨.
- setState(result.message) 호출 시, result.message가 원시값이라면 그 값도 state에 복사됨.
- 원시값은 복사되어 state로 저장되므로, 메모리에는 parse.data와 state에 각각 독립적으로 값이 존재하게 됨.
ㄹ. 결론
- 객체일 때: 메모리 사용이 효율적임. setState(result.message)는 state에 result.message의 참조값을 할당하므로, 객체가 실제로 복사되지 않고, 메모리에서 객체 하나만 차지함.
- 원시값일 때: 원시값이 복사되어 메모리에서 두 번 저장됨. 하지만 원시값은 일반적으로 메모리 사용량이 적음.