참조 타입과 참조 복사

객체·배열·함수를 담은 변수에는 값이 아니라 객체의 참조가 저장된다. 대입하면 참조가 복사되므로 두 변수가 같은 객체를 가리킨다.

Seobway · · 7분

문제 상황

원시 타입은 대입할 때 값이 복사되어 두 변수가 서로 영향을 주지 않는다.
객체는 다르게 동작한다.

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

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

copy = original 에서 복사되는 것은 객체가 아니라 객체의 참조다. 두 변수가 같은 객체를 가리키므로
한쪽에서 속성을 바꾸면 다른 쪽에서도 바뀐 값이 보인다.


동작 원리

참조 타입은 변수에 값 대신 참조(reference), 즉 힙에 할당된 객체의 위치 정보가 저장되는 타입이다.
원시 타입 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 결과를 비교하는 방법도 있지만
속성 순서, undefined·함수 값 누락 때문에 정확하지 않다.


예제

참조 복사와 스프레드 복사의 차이를 비교한다.

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 사양

관련 글