반응형
원시값(Primitive)과 객체(Object) 비교
구붐 | 원시값(Primitive) | 객체(Object) |
정의 | 자바스크립트에서 더 이상 쪼갤 수 없는 기본 데이터 타입 | 원시값이 아닌 모든 데이터 타입 |
종류 | string, number, boolean, null, undefined, symbol, bigint | Object, Array, Function, Date 등 |
메모리 저장 방식 | 스택(Stack) 영역에 직접 값 저장 | 힙(Heap) 영역에 값 저장, 스택에는 힙 주소(참조) 저장 |
변경 가능 여부 | 불변(Immutable) – 값 자체를 변경할 수 없음 | 가변(Mutable) – 객체 내부 속성 변경 가능 |
복사 방식 | 값 자체가 복사됨 (값 복사) | 참조값이 복사됨 (참조 복사) |
값 복사(Value Copy) 와 참조 복사 (Reference Copy)
값 복사(Value Copy) – 원시값
- 원시값은 값 자체가 복사됨
- 값 자체를 복사 → 서로 독립
- 즉, 한 변수의 값을 다른 변수에 할당해도 서로 영향을 주지 않음
- 대상 : 원시값(숫자, 문자열, boolean 등)
let a = 10;
let b = a; // a의 값을 b에 복사
b = 20;
console.log(a); // 10
console.log(b); // 20
/*
- a와 b는 서로 독립적임.
- 원시값은 스택 메모리에 바로 저장되기 때문에 값 자체가 복사됨
*/
참조 복사(Reference Copy) – 객체
- 객체는 힙 메모리에 저장되고, 변수에는 객체의 주소값(참조)가 저장됨
- 변수에 객체의 주소를 복사 → 변경 시 원본 영향
- 대상 : 객체, 배열, 함수
let obj1 = { name: "Alice" };
let obj2 = obj1; // obj1의 참조를 obj2에 복사
obj2.name = "Bob";
console.log(obj1.name); // "Bob"
console.log(obj2.name); // "Bob"
/*
- obj1과 obj2는 같은 객체를 가리키므로, 한 쪽에서 바꾸면 다른 쪽도 영향을 받음.
- 주소값이 복사되었지, 실제 값이 복사된 것은 아님.
*/
✓ 참조 = 지도 → 참조/주소
값 복사 vs 참조 복사
항목 | 값 복사(Value Copy) | 참조 복사(Reference Copy) |
대상 | 원시값 | 객체, 배열, 함수 등 |
메모리 | 값 자체를 복사 | 참조 주소를 복사 |
변경 시 영향 | 독립적, 서로 영향 없음 | 동일 객체를 참조하므로 서로 영향 있음 |
예시 | let b = a (원시값) | let b = obj (객체) |
얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)
얕은 복사(Shallow Copy)
- 최상위 속성만 새로 복사, 중첩 객체는 공유
- 객체나 배열을 복사할 때 최상위 레벨만 새로운 객체/배열로 생성
- 내부에 중첩된 객체나 배열은 원본과 같은 메모리 주소(참조)를 공유 - 중첩 객체까지는 새로 복사하지 않음
- 따라서 중첩된 객체/배열을 변경하면 원본에도 영향이 있음
- 대상 : 객체, 배열
✓ 얕은 → 겉만 새로 만들고 깊이는 그대로
특징
항목 | 내용 |
복사 범위 | 최상위 객체/배열만 복사 |
내부 객체/배열 | 참조 공유 |
원본 영향 | 최상위 변경 → 영향 없음(독릭접), 중첩 변경 → 영향 있음(원본과 공유) |
대표 메서드 | concat(), slice(), map(), filter(), reduce(), Array.from(), [...spread] |
얕은 복사에 해당하는 메서드/연산
- 배열 관련: concat(), slice(), map(), filter(), reduce(), Array.from()
- ES6 스프레드 연산자: [...arr], { ...obj }, Object.assign({}, obj)
let arr1 = [1, 2, { a: 10 }];
let arr2 = arr1.slice(); // 얕은 복사
arr2[0] = 100; // 최상위 값 변경
console.log(arr1[0]); // 1 → 원본 영향 없음
arr2[2].a = 50; // 중첩 객체 변경
console.log(arr1[2].a); // 50 → 원본도 변경됨
let obj1 = {
name: "Alice",
info: { age: 25, city: "Seoul" }
};
// 얕은 복사
let obj2 = { ...obj1 }; // 스프레드 연산자 사용
obj2.name = "Bob"; // 최상위 속성 변경
obj2.info.age = 30; // 중첩 객체 속성 변경
console.log(obj1.name); // "Alice" → 최상위 속성은 독립적
console.log(obj1.info.age); // 30 → 중첩 객체는 참조 공유
/*
- 최상위 속성은 새로 생성
- 중첩 객체는 참조를 공유 → 변경하면 원본에도 영향
*/
1. Object.assign()을 활용한 복사
- 대상 : 객체
- 복사 범위 : 최상위 속성만 → 얕은 복사
- 여러 객체를 병합할 때 유용
/* [문법] */
Object.assign(복사된 속성이 들어갈 객체, 복사한 원본 객체(들))
/* [문법] - 새 객체를 만들려면 빈 객체 {}를 대상객체로 사용 */
Object.assign({}, 복사한 원본 객체(들));
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = Object.assign({}, obj1); // obj1을 obj2로 얕은 복사
obj2.a = 10; // 최상위 속성 변경
console.log(obj1.a); // 1 → 원본 영향 없음
obj2.b.c = 20; // 중첩 객체 속성 변경
console.log(obj1.b.c); // 20 → 원본도 영향
let objA = { x: 1 };
let objB = { y: 2 };
let merged = Object.assign({}, objA, objB);
console.log(merged); // { x: 1, y: 2 }
2. 스프레드 연산자(...)를 활용한 복사
- 대상 : 객체, 배열(배열은 [...arr])
- 최상위 속성만 → 얕은 복사
- 문법이 간단, 직관적
/* [문법] */
let 새객체 = { ...원본객체 };
let 새배열 = [...원본배열];
// 객체 복사 예
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { ...obj1 }; // 얕은 복사
obj2.a = 10;
console.log(obj1.a); // 1 → 독립적
obj2.b.c = 20;
console.log(obj1.b.c); // 20 → 중첩 객체는 공유
// 배열 복사 예
let arr1 = [1, 2, { x: 10 }];
let arr2 = [...arr1]; // 얕은 복사
arr2[0] = 100;
console.log(arr1[0]); // 1 → 독립적
arr2[2].x = 50;
console.log(arr1[2].x); // 50 → 내부 객체는 공유
깊은 복사(Deep Copy)
- 모든 속성, 중첩 객체/배열까지 새로 복사 → 완전 독립
- 객체 내부의 모든 속성, 중첩 객체, 배열까지 재귀적으로 새 객체 생성
- 원본과 완전히 독립
- 대상 : 객체 배열
특징
- 원본 객체와 완전히 분리
- 중첩된 객체/배열 변경 시 원본에 영향 없음
let obj1 = {
name: "Alice",
info: { age: 25, city: "Seoul" }
};
// 깊은 복사
let obj2 = JSON.parse(JSON.stringify(obj1));
obj2.name = "Bob";
obj2.info.age = 30;
console.log(obj1.name); // "Alice" → 원본 영향 없음
console.log(obj1.info.age); // 25 → 중첩 객체도 독립적
/* ※
- JSON.stringify 방식은 함수, undefined, Symbol 등을 처리하지 못함
- 실무에서는 Lodash 같은 라이브러리의 _.cloneDeep()을 많이 사용
*/
1. JSON 방식을 활용한 복사 : JSON.parse(JSON.stringify(obj))
기본 원리
- JSON.stringify(obj) → 객체를 JSON 문자열로 변환
- JSON.parse(...) → JSON 문자열을 다시 객체로 변환
- 결과: 중첩 객체/배열까지 모두 새로 생성 → 완전한 깊은 복사
- 모든 자료형을 안전하게 복사하고 싶으면 _.cloneDeep(obj) 홀용
장점
- 모든 자료형(객체, 배열, Date, Map, Set 등)을 안전하게 깊은 복사 가능
- 함수, Symbol 등 특수값도 안전하게 처리
- JSON 방식보다 더 완벽한 깊은 복사
단점
- 큰 객체일 경우 성능 부담
import _ from "lodash";
let obj1 = {
a: 1,
b: { c: 2 },
d: [3, 4],
e: new Date()
};
let obj2 = _.cloneDeep(obj1);
obj2.b.c = 100;
obj2.d[0] = 50;
console.log(obj1.b.c); // 2 → 원본 영향 없음
console.log(obj1.d[0]); // 3 → 원본 영향 없음
console.log(obj1.e === obj2.e); // false → Date 객체도 새로 생성
얕은 복사 vs 깊은 복사
구분 | 얕은 복사 | 깊은 복사 |
복사 범위 | 최상위 속성만 | 중첩 객체/배열까지 재귀적으로 모두 |
내부 객체/배열 | 참조 공유 | 새 객체/배열 생성 |
원본 영향 | 중첩 객체 변경 시 영향 있음 | 원본에 영향 없음 |
방법 | 스르페드 연산자, Object.assign() | JSON.parse(JSON.stringify(obj)), _.cloneDeep() |
반응형
'JS > Javascript' 카테고리의 다른 글
[javascript] 객체 8 / 객체에서의 this (0) | 2025.09.03 |
---|---|
[javascript] 객체 7 / 객체 내장 메서드 (0) | 2025.09.02 |
[javascript] 객체 5 / 객체 존재 여부 확인, 반복 (in 연산자, hasOwnProperty(), for...in) (0) | 2025.08.21 |
[javascript] 객체 4 / 객체 삭제 (0) | 2025.08.21 |
[javascript] 객체 3 / 객체 수정, 객체 추가 (0) | 2025.08.21 |