2024. 7. 25. 02:08ㆍ프로그래밍/JavaScript
개요
Javascript에서 변수 및 객체가 내부적으로 어떤 동작 원리에 의해 복사되고 할당되는지 알아본다.
Javascript에는 C처러 포인터의 개념이 없기 때문에 메모리에 변수의 값을 할당하는 부분을 신경써주지 않아도 된다.
그렇다면 변수나 객체를 복사했을 때는 어떻게 될까?
변수의 경우에는 결론적으로 말하자면 서로 같은 원시타입(primitive type)이 값을 갖고 있다 하더라도 서로 해당 값을 가르키는 메모리의 주소가 다르다. 변수를 2개 선언했다면 식별자도 다를 것이다.
또한 Javascript에서는 객체를 변경가능하게끔 설계했다. 만약 위에서 설명한 변수가 복사되는 원리로 객체를 복사하게 되면 오버헤드가 커지고 성능이 저하 되게 될 것이다. 객체는 훨씬 더 많은 메모리를 사용할 것이기 때문이다.
따라서 하나의 객체에서 프로퍼티를 추가 제거, 값을 변경하는 등의 작업을 하나의 메모리 주소에서 모두 수행한다.
이와 관련된 개념을 얕은 복사, 깊은 복사 라고 한다.
이로 인해 발생하는 문제점을 알아보자
문제점
만약 객체를 복사하게 된다면 개발자의 의도대로 동작하지 않을 수도 있다.
const obj1 = {
x:10,
y:20
}
const obj2 = obj1; # 객체 obj1의 메모리 주소를 obj2가 참조
obj2.x = 30; # obj1과 obj2가 바라보고 있는 메모리 주소의 객체 프로퍼티 x의 값을 변경
console.log(obj1.x)# obj객체의 프로퍼티 값이 변경됨
위 결과를 보게 되면 당연한 결과가 나온다. 일반적으로 다른 프로그래밍 언어에서도 객체를 복사해서 사용하게 되면 실질적으로는 객체의 주소를 참조하게 되고 이는 곧 같은 메모리 주소를 가르키는 것을 뜻하기 때문이다.
얕은 복사
const obj1 = {
x:{
z: 50
},
y:20
}
const obj2 = { ...obj1 };
console.log(obj1 === obj2); # false
console.log(obj1.x === obj2.x); # true
위 와 같이 객체를 복사하게 되면 새로운 객체를 생성한 것이므로 객체를 값으로 갖는 식별자의 메모리 주소는 서로 다른 주소를 가르키게 되므로 false가 출력된다. 그러나 객체안의 객체가 있는 경우에는 완벽하게 복사된 것이 아니라 true가 된다. 즉 key가 x인 객체는 obj1과 obj2가 서로 같은 객체를 가르키고 있다는 뜻이 된다. 이를 얕은 복사라고 한다. 여기서 말하는 복사란 값은 같으면서 서로 다른 주소값을 가져서 reference by value가 일어나지 않게 복사가 됐다는 뜻이다.
참고로 빌트인 메서드인 Object.create이나 Object.assign 등은 얕은 복사를 수행한다.
배열의 경우 객체와는 조금 다르다.
const ingredientsList = ["noodles", { list: ["eggs", "flour", "water"] }];
const ingredientsListCopy = Array.from(ingredientsList);
console.log(ingredientsListCopy);
// ["noodles",{"list":["eggs","flour","water"]}]
ingredientList[0] = 'test';
console.log(ingredientsListCopy[0]);
Copy 배열은 test로 변경한 값이 출력되지 않는다.
그럼 다음 동작을 예측해보자.
const obj1 = {
x:{
z: 50
},
y:20
}
const obj2 = { ...obj1 };
console.log(obj1 === obj2);
obj1.a = 30;
console.log(obj1)
console.log(obj2)
console.log(obj1.x === obj2.x);
obj1.x.z = 100;
console.log(obj1)
console.log(obj2)
객체인 obj1과 obj2는 다른 객체이므로 obj1.a라는 프로퍼티를 추가하더라도 obj2에는 새로운 프로퍼티가 할당되지 않는다.
그러나 obj1.x와 obj2.x는 서로 같은 값이다. 즉 같은 객체를 가르키고 있으므로 해당 객체 내부의 프로퍼티를 수정하면 같이 변경된다.
따라서 obj1과 obj2의 x객체 내부의 z프로퍼티의 값은 둘 다 100으로 변경되게 된다.
깊은 복사는 라이브러리를 사용해 구현할 수 있으므로 참고.
깊은 복사
객체 전체가 서로 다른 주소값을 가지게끔 완벽하게 본사된 것을 뜻하며 이를 위해서 MDN에서는 직렬화 역직렬화를 가지는 방법을 설명해주고 있다. 깊은 복사를 수행하게 되면 서로 참조하는 값 없이 완벽하게 복사가 된다.
출처 :
https://developer.mozilla.org/ko/docs/Glossary/Shallow_copy https://developer.mozilla.org/ko/docs/Glossary/Deep_copy
'프로그래밍 > JavaScript' 카테고리의 다른 글
encodeURI와 encodeURIComponent의 차이점 (2) | 2024.09.04 |
---|---|
[ Javascript ] 함수 호이스팅, 함수 선언문과 표현식, 함수 리터럴 (0) | 2024.07.28 |
[ Javascript ] 암묵적 캐스팅과 산술 연산자 +의 문자열 형변환 (0) | 2024.07.19 |
[ Javascript ] Javascript의 변수 선언과 초기화 동작 원리 및 숫자(number) 타입의 크기 (0) | 2024.07.18 |
Javascript try-catch 동작 원리, return과 error의 차이점 (0) | 2023.11.20 |