참조 타입 — 주소가 복사되는 것들

객체·배열·함수는 변수에 값이 아니라 주소가 담긴다. 복사해도 같은 것을 가리켜서 한쪽을 고치면 둘 다 바뀐다.

Seobway · · 7분

복사한 객체를 고쳤는데 왜 원본까지 바뀌는가

원시 타입은 값이 복사되어 서로 독립적이었다. 객체는 다르다.

const original = { name: "서브웨이" };
const copy = original;

copy.name = "바뀜";
console.log(original.name);   // "바뀜"   ← 원본까지 바뀐다

복사한 것은 객체가 아니라 객체를 가리키는 주소이기 때문이다.


참조 타입은 무엇인가

참조 타입은 변수에 값이 아니라 메모리 주소(참조)가 저장되는 타입이다.
원시 타입 7가지가 아닌 것은 전부 참조 타입이다.

변수에 담기는 것은 실제 데이터가 아니라 "그 데이터가 어디 있는지" 다.
그래서 두 변수에 같은 주소가 들어가면 둘은 같은 하나를 본다.

인터랙티브 다이어그램: 참조 타입은 주소가 복사된다 (단계별로 재생할 수 있다)

  1. const original = { name: "서브웨이" } — 객체가 어딘가에 만들어진다.
  2. original 에는 객체가 아니라 그 객체의 주소가 담긴다.
  3. const copy = original — 복사되는 것은 주소다. 객체는 그대로 하나다.
  4. copy.name 을 고치면 주소를 따라가 그 하나뿐인 객체를 고친다.
  5. original 로 읽어도 같은 객체라 바뀐 값이 보인다.


비교도 주소로 한다

=== 는 참조 타입에서 내용이 같은지가 아니라 같은 객체인지를 본다.

{ a: 1 } === { a: 1 }    // false — 내용은 같지만 서로 다른 객체
[1, 2] === [1, 2]        // false

const x = { a: 1 };
const y = x;
x === y                  // true — 같은 주소

내용을 비교하려면 직접 비교하거나 JSON.stringify 같은 우회를 써야 한다
(중첩·순서·함수 때문에 완전하지는 않다).


직접 확인

같은 객체를 가리키는지, 따로인지 눈으로 확인해라.

const original = { name: "서브웨이", tags: ["js"] };

const alias = original;              // 주소 복사 — 같은 객체
const shallow = { ...original };     // 얕은 복사 — 겉만 새 객체

alias.name = "별칭이 바꿈";
console.log("1:", original.name);    // 바뀐다

shallow.name = "복사본이 바꿈";
console.log("2:", original.name);    // 안 바뀐다

// 그런데 중첩된 배열은 여전히 공유된다
shallow.tags.push("ts");
console.log("3:", original.tags);    // 같이 바뀐다!

console.log("같은 객체?", original === alias, original === shallow);

3번이 핵심이다. { ...original }최상위 속성만 새로 만들고, 그 안의 배열은
주소만 복사한다. 이것이 얕은 복사와 깊은 복사가 갈리는 지점이다.


흔한 실수


한 줄 정리

참조 타입은 변수에 주소가 저장되는 타입(객체·배열·함수)이다. 대입·인자 전달은
주소를 복사하므로 여러 변수가 같은 하나를 가리키고, === 도 내용이 아니라 주소를 비교한다.

참고

  1. [1] JavaScript data types and data structures — MDN Web Docs
  2. [2] Object — MDN Web Docs
  3. [3] The Object Type — ECMAScript 사양

관련 글