자바스크립트에서 사용되는 데이터는 원시형데이터와 참조형 데이터로 나뉘게 됩니다.
원시데이터(String, Number, Boolean, undefined, null)
참조형 데이터(Object, Array, Function)
let
이나 const
로 데이터가 할당이 되게 되면 그 데이터는 지정된 메모리 주소로 들어가게 됩니다. 즉, let a = 1;
에서 a는 1이 아니라 1의 정보가 들어있는 메모리 주소를 가르키게 되는 것입니다. console.log(a)
와 같이 a 값을 확인해보면 1이 들어있는 메모리주소에서 1을 꺼내와 콘솔창에 출력을 하게 되는 것이죠
먼저, 원시형데이터의 예시를 통해 할당과 메모리 주소를 살펴보도록 하겠습니다.
let a = 1
let b = 4
console.log(a, b, a === b) // 값: 1 4 false
현재 작성된 코드의 경우 a가 가르키는 메모리 주소와 b가 가르키는 메모리 주소가 다르기 때문에 false가 출력되게 되는 것입니다.
b = a // 변수 b에 a가 바라보는 메모리의 주소를 할당
console.log(a, b, a === b) // 값: 1 1 true
만약 위와 같이 b에 a가 가르키는 메모리 주소를 할당하는 경우 a와 b는 동일한 메모리주소를 바라보고 있기 때문에 true가 출력이 되게 됩니다.
그렇다면 a에 새로운 값을 재할당하게 되면 어떻게 될까요?
a = 7 // a에 다른 데이터가 들어가므로 다른 메모리 주소가 할당됨
console.log(a, b, a === b) // 값: 7 1 false
이런 경우 a는 더이상 1이 들어있던 메모리 주소를 바라보지 않고 7이 들어갈 새로운 메모리 주소를 만들어 그 주소를 바라보게 됩니다.
그렇다면 만약, 앞에서 할당이 이미 한번 이뤄졌던 숫자 1을 c에 할당을 하게 되면 어떻게 될까요?
let c = 1
console.log(b, c, b === c) // 값: 1 1 true
// c는 새로운 변수지만 원래 있던 데이터 값인 1이 할당되었으므로
// b와 c가 가리키는 메모리 주소가 같아서 true가 반환됨
할당된 원시데이터가 기존 메모리 주소에 들어가 있는 경우 새롭게 메모리주소를 만들지 않고 그 메모리 주소가 할당되게 됩니다. 이를 데이터 불변성이라고 합니다.
처음 접하는 내용이라면 이해하기가 더 복잡할 수 있는데 사실상 원시형 데이터의 경우 데이터 자체가 변하지 않은 성질을 가지고 있기 때문에(데이터불변성), 메모리 주소까지 참조해서 비교하며 이해할 필요 없이 생긴 모습이 똑같으면 같은 데이터라고 이해를 해도 괜찮습니다.
하지만 참조형 새로운 데이터를 만들 때마다 새로운 메모리 주소에 할당되게 됩니다.(가변성) 따라서 똑같이 생긴 데이터라고 해도 가르키는 메모리 주소가 다르기 때문에 다를 수 있는 것입니다.
let a = { k: 1 }
let b = { k: 1 }
console.log(a, b, a === b)
// 값: { k: 1 }, { k: 1 }, false
// 변수 a와 b가 바라보는 메모리 주소가 다르므로 false
현재 { k:1 }
로 a와 b에 할당된 데이터의 모양은 똑같지만, 각각 다른 메모리 주소가 할당되었기 때문에 둘을 비교해보면 false라는 것을 알 수 있습니다.
만약, 아래와 같이 a의 k속성의 값이 1에서 7로 변경되는 경우 b=a는 같을까요? 또는 다를까요?
a.k = 7
b = a
console.log(a, b, a === b)
현재 a가 가르키는 메모리 주소의 k를 숫자 1에서 7로 변경을 한 후 그 메무리 주소를 b에 할당을 했기 때문에 결론적으로는 변수 a와 b가 바라보는 메모리 주소가 같습니다.
따라서 a와 b모두 숫자 7이 들어있는 객체 데이터 값을 반환하며 둘의 메모리 주소는 동일하다는 것을 알 수 있습니다({ k: 7 }, { k: 7 }, true
)
이렇게 변수 b에 변수 a를 할당하는 경우 값이 할당되는 것이 아니라 메모리 주소가 할당되는 것이기 때문에 주의해서 사용을 해야합니다.
아래 예시를 살펴보도록 하겠습니다.
a.k = 2 // a 객체 데이터의 속성 값만 바꿈
console.log(a, b, a === b)// { k: 2 }, { k: 2 }, true
a가 가르키는 주소의 객체데이터에서 k의 값을 7에서 2로 변경을 한 후 a와 b의 값을 출력해보면 b의 값 역시 변경된 것을 확인할 수 있습니다. 즉, a와 b가 바라보는 메모리 주소가 같으므로 b의 객체 데이터의 속성 값도 함께 바뀌게 되는 것입니다.
let c = b
console.log(a, b, c, a === c) // { k: 2 }, { k: 2 }, { k: 2 }, true
a.k = 9
console.log(a, b, c, a === c)
// 값: { k: 9 }, { k: 9 }, { k: 9 }, true
// 이또한 a의 k 속성 값만 바꿨지만 메모리 주소가 같아 b, c 속성 값 모두 바뀜
결국 참조형 데이터는 할당 연산자를 사용할 때 새로운 데이터가 만들어지는 개념(복사X)이 아니라, 단순히 메모리의 참조 주소만 옮겨가게 되는 것입니다.
이러한 이유로 복잡한 웹 사이트를 만들 때 하나를 수정했는데 의도치 않게 다른 부분도 수정되는 결과를 가져올 수 있습니다.
따라서 참조형 데이터에 다른 데이터를 재할당 할 때는 복사라는 개념을 사용하게 됩니다.
원시형 데이터
- 한번 할당된 메모리 주소는 변하지 않습니다. (데이터 불변성)
- 사실 상 같은 모양의 데이터는 같다고 봐도 무방합니다.
참조형 데이터- 선언 할 때 마다 새로운 메모리 주소가 할당됩니다. (데이터 가변성)
- 데이터의 생김새가 같더라도 다를 수 있습니다.
- 같은 주소를 가르키는 변수들이 있을 때 하나를 수정하게 되면 같은 주소를 가르키는 모든 변수들의 값도 수정되게 되기에 주의해서 사용을 해야합니다.