출처: 유데미
위의 자료에서 볼 수 있듯이 primitive type은 call stack에 저장되어지고 reference type은 heap에 저장되어진다.
출처: 유데미
각각 코드를 보면서 어떻게 자바스크립트에서 작동되는지를 배웠는데 정말 흥미로웠다.
primitive value는 아까 말했듯이 call stack에 저장된다. 여기서 변수 이름들이 identifier가 되고 각 변수들은 주소와 값을 가지게 된다. let age =30
이므로 identifier에 age가 저장되고 address 0001 그리고 값 30을 가지게 되는 것이다. 여기서 let oldAge = age를 해주었으므로 age와 oldAge 둘다 주소 0001를 가르키게 된다. 그런데 age=31;로 age에 새로운 값을 넣어준 상황에서 원래 가르키고 있던 주소 0001의 값 30이 31로 달라지는 것이 아니라 새로운 값 31을 가지고 있는 새 주소 0002를 가르키게 되는 것이다.
이러한 원리로 위 자료에서 보이는 첫번째 코드에서console.log(age) 는 값이 31이 나오고 console.log(oldAge)는 값이 30이 나오는것이다!
다음으로 reference type은 값이 heap에 저장되지만, 바로 heap에서 접근하는 것이 아니라 먼저 콜스택에서 address와 값을 생성한 후 그 값을 참조하여 heap에 있는 주소로 접근하게 되는 것이다. primitive type과 다르게 값이 변화하게 되면 여기서는 같은 주소를 가지고 그 값를 참조하여 heap에 있는 주소로 간 뒤 그 주소의 값을 변경하게 되는것이다. 그러한 이유로 두번째 코드에서 friend 객체에서만 나이를 27로 바꿨는데 콘솔로그로 확인해보면 me 객체에서의 나이로 27로 바뀐 것이다.
Reference type에서
const jessica = {
firstName: 'Jessica',
lastName: 'Williams',
age: 27,
};
const marriedJessica = jessica;
marriedJessica.lastName = 'Davis';
console.log('Before marriage:', jessica);
console.log('After marriage:', marriedJessica);
const인데 marriedJessica.lastName을 'davis'로 바꾸는게 가능하나라는 생각이 들 수 있는데 위에 공부했듯이 변수의 할당을 바꾸는게 아니라 heap에 있는 property만 바꿔준 것이기 때문에 상관이 없다.
안되는 것은
marriedJessica = {};
이런식으로 object 내용 자체를 바꾸려고 할때 안되는것이다.
이렇게 object는 안에 있는 property를 수정하면 본래의 object이 수정되는데, 만약 원래 객체를 수정하지 않으려면 이 object를 복사해주는 방법을 쓰면 된다.예시는 아래와 같다.
const jessica2 = {
firstName: 'Jessica',
lastName: 'Williams',
age: 27,
family: ['Alice', 'Bob'],
};
const jessicaCopy = Object.assign({}, jessica2);
jessicaCopy.lastName = 'Davis';
console.log('Before marriage:', jessica2);
console.log('After marriage:', jessicaCopy);
이렇게 Object.assign이라는걸 이용해서 object를 카피해줄 수 있다
.즉, 복사하여서 새로운 객체를 새로운 식별자 이름으로 만들어 주는 것이다. 근데 여기서 알아야할 점이 있는데 이건 first level에 있는 properties만 복사해주는 shallow copy라는 것이다.
그래서 만약 객체에 array같은 첫번째 레벨에 없는 것들이 존재하면 이건 원래 존재하던 객체를 참조하게 된다. 위의 코드를 보면 Object.assign을 사용하여 jessica2를 jessicaCopy로 복사한다. 이때jessicaCopy의 lastName을 'Davis'로 변경하면, jessica2의 lastName은 영향을 받지 않는다. 하지만, 배열과 같은 중첩된 객체는 여전히 원본과 같은 참조를 가지므로
, 변경 사항이 두 객체 모두에 영향을 미친다. 아래의 예시 코드를 보자.`
jessicaCopy.family.push('Mary');
jessicaCopy.family.push('John');
console.log('Before marriage:', jessica2);
console.log('After marriage:', jessicaCopy);
이런식으로 family에 배열 추가해주면 새로 복사한 객체와 원래 존재하던 객체가 둘다 push한 값을 가지고 있는 것을 볼 수 있다. 즉, 복사해서 새로운 객체임에도 불구하고 first level에 없는 array같은 것들은 원래의 객체를 참조하여 원본 객체도 수정되는 것이다.
좋은 내용의 글 감사합니다! 좀 더 찾아보고 싶은데 혹시 출처가 어디일까요?