ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Javascript] 원시 값과 참조 값
    개발일지/FE 2023. 2. 21. 10:47
    반응형

    Javascript의 값에는 두 가지 종류의 카테고리가 존재한다.

    바로 원시 값과 참조 값이다.

    오늘은 두개의 차이에 대해 공부하고 포스팅 해보고자 한다.

     


     

    자바스크립트의 7개 대표적인 값(String, Number, Boolean etc)의 경우 원시 값이라고 할 수 있다.

    원시 값은 메모리에 저장되고 보통 스택이다.

    상대적으로 짧게 동작하기 때문인데,

    이 값은 자바스크립트가 쉽게 제거할 수 있고 또한 비용이 저렴하기에 쉽게 복제할 수 있다.

    이곳에서 보통 스택이라고 말한 것의 의미는

    만약 작업이 길어지게 될 경우 힙에 저장하여 장기적으로 사용할 수도 있다는 의미이다.

     

    원시 값에서 변수를 복사한다는 것은

    원시 값을 가진 새로운 변수를 할당한 뒤 실제로 값을 할당한다는 것이다.

    조금 복잡하게 설명했는데 예시를 들자면 두 개의 변수가 있다고 생각해 보자.

    let name = "Max";
    let anotherUser = name;
    name="Manuel";
    

     

    다음과 같은 코드가 존재한다고 했을 때 모두가 예상하겠지만,

    name의 값이 변경되어도 anotherUser의 값은 그대로이다.

    왜냐하면 anotherUser는

    새로운 원시 값(string)을 가진 변수 anotherUser에

    name이라는 변수에 있는 값을 복사하여 저장한 것이기 때문이다.

     

    여기서 참고할 수 있는 것이 바로 깊은 복사(deep copy)얕은 복사(shallow copy)이다.

    원시 값은 깊은 복사에 해당한다.

     

    깊은 복사란 말 그대로 주소가 가지고 있는 값

    즉 변수의 값을 실제로 다른 메모리 공간에 할당하고 그 값을 가르키는 주소인 변수를 새로 생성한다.

     

    두 개의 변수는 같은 값을 가지고 있지만 서로 영향을 미치지 않으며

    심지어는 메모리 공간을 가리키는 주소 역시 다르다고 볼 수 있다.

    반대로 생각해보면 얕은 복사는

    가리키고 있는 주소 값이 같기 때문에(즉, 참조된 메모리 공간이 동일하기 때문에)

    만약 메모리 공간 안의 값이 변경될 경우 동일하게 다른 그 주소를 가리키고 있는 다른 하나 역시 변경되는 것이다.

     

    그렇다면 참조 값은 얕은 복사라고 볼 수 있겠으며,

    또한 모든 object를 뜻한다고 볼 수 있다.

    object 라고 하면 일전 null과 undefine을 비교했을 때 object라고 하지 않았냐고 할 수 있다.

    실제로 null의 typeof를 콘솔에서 확인했을 때 object임을 확인할 수 있다.

    하단은 null과 관련된 포스팅이다.

    https://coding7281.tistory.com/18

    좀 더 정확하게 말하자면 null을 비롯한 원시 값의 일곱 종류(String, Number 등)가 있고

    이 원시 값의 이름을 그대로 차용하여 원시 래퍼 객체(Wrapper object)를 만들었다.

     

    도대체 이게 무슨 소리인가 싶을 수 있다.

    (나도 정리하면서 3번은 다시 확인한 것 같다..)

     

     우리는 이쯤에서 원시 값의 정의를 봐야 할 필요성을 느낀다.

     

    ✨ 원시 값이란, 객체 가 아니면서 메서드 도 가지지 않는 데이터이며 불변 하여 변형을 할 수 없다.

     

    그러나 우리는 String을 let이라는 변수를 이용해 값을 변형 하기도 하고,

    또한 객체처럼 메서드를 활용하기도 한다. (ex) .toUpperCase()와 같이

    예를 들어 다음과 같은 코드가 존재한다.

    let bar = "baz"
    bar = bar.toUpperCase(); //BAZ
    

     

    이 코드는 bar이 가지고 있던 baz라는 값을 변형시키는 것이 아닌 새로운 값을 부여하는 것이다.

    즉 불변하는 원시 값의 규칙을 지키고 있는 것이다.

     

    또 이때 사용된 .toUpperCase()는 래퍼 객체로써

    bar의 원시 값의 프로퍼티에 접근할 수 있도록 하는데

    객체는 프로퍼티에 접근 시에만 특별히 만들어졌다가

    값을 bar에 부여한 뒤 원시 값 string만 남도록 객체가 사라진다.

     

    ✨ 그러니까 정리하자면 원시 값의 7종류와 동일하게 원시 래퍼 객체가 존재하는 것이고 변수에 값을 할당한 뒤 값 변형이나 프로퍼티 접근 등을 위해 원시 값 7종류와 동일한 이름을 가진 원시 래퍼 객체를 일시적으로 생성한 뒤 값 변형이 끝나면 원시 값만 남긴다는 의미이다.

     이런 의미에서 원시 값은 동적으로 변하는 의사 객체라고 할 수 있다.

     

    일시적인 객체로 변하는 원시 값과 다르게

    참조 값은 늘 객체 형태를 유지하고 변형 시에도 값 자체를 변형한다.

     

    참조 값은 객체이기 때문에 비용이 보다 더 많이 들고 많은 메모리 영역을 차지하게 된다.

    그렇기 때문에 스택보다는 힙에 저장된다.

    이때 원시 값과 다른 점은 변수가 값 자체를 가리키고 있는 것이 아닌,

    메모리 공간의 주소만을 저장하고 있다는 점이다.

     

    즉 깊은 복사와 얕은 복사의 예를 들자면

    두 개의 변수가 한개의 객체를 가리키고 있을 때,

    만약 한 변수로 가리키고 있는 객체 값을 변경하게 되면

    다른 변수에서도 확인 시 값이 변경된 점을 확인할 수 있다.

     

    즉 참조 값은 메모리 공간을 가리키는 포인터라고 할 수 있다.

     

    참조 값에 얕은 복사가 발생하는 것은 데이터의 불필요한 복제를 피하고

    메모리가 차는 것을 방지하여 더 나은 성능을 제공하기 위함이다.

     

    그렇다면 참조 값은 깊은 복사를 할 수 없을까?

    그것은 아니다.

    우리에게는 javascript에서 제공하는 spread 연산자 이 존재한다.

     

    해당 연산자를 사용할 경우 다음과 같이 key와 value이 Person과 동일하게 복사되고 별도의 객체가 형성되는 셈이다.

    이렇듯 참조 값 역시 깊은 복사가 가능하다.

     

    찝찝하게 끝난 것 같은데 결국 원시 값과 참조 값은 javascript 엔진에서 힙 그리고 스택과 관련이 있다.

    이는 다시 말하면 장기 메모리와 단기 메모리의 차이이고 비용의 차이이기도 하다.

    자세한 것은 MDN문서를 추가로 확인해보는 것이 좋을 것 같다. 


    💜

     

    해당 게시글은 MDN 공식 문서 및 Udemy 강의를 참고하여 만들어졌습니다.

    틀린 부분이 있다면 댓글 주시면 수정하겠습니다.

    감사합니다 😊

     

     

    반응형
Designed by Tistory.