JS> 원시 값 & 객체

OwlCJ·2022년 2월 6일
0

Javascript

목록 보기
4/6

오늘은 모던 자바스크립트 DeepDive를 읽다 원시값과 객체의 비교 부분을 포스팅해보려고한다.
메모리 부분에서 정확히 이해가 되지 않았지만 추후에 다시 확인해보기 위해 포스팅한다.✍🏻

자바스크립트가 제공하는 데이터타입은 크게 원시타입과 객체타입으로 구분할 수 있다.

원시 타입과 객체 타입은 크게 두가지가 다르다.

  • 원시 타입의 값은 변경 불가능한 값이다. 객체 타입의 값은 변경 가능한 값이다.
  • 원시 값을 변수에 할당할 시 변수에 실제 값(원본의 값이 복사되어 전달/call by value)이 저장된다. 이에 반해 객체를 변수에 할당하면 변수에는 참조 값(원본의 주소 값이 전달/call by reference)이 저장된다.

(다만 학습에 참고한 모던 자바스크립트 DeepDive에 의하면 자바스크립트는 ECMAscript사양에 엔진의 작동방식을 정의한 공식적인 명칭이 없다고 한다. 구분하는 의미에서 타 언어의 구분법을 차용한 것이라 오류가 있을 수 있다함.)

원시 값

원시 타입의 값은 변경 불가능한 값이다. 한번 생성된 원시 값은 읽기 전용으로 변경할 수 없다.
변수의 값을 변경할 수 없다는 말로 오해할 수 있지만, 어떤 주소에 할당된 값 자체를 변경할 수 없다는 뜻이지 변수의 값을 변경할 수 없는 것은 아니다.

예로 let a = 123 이라고 할당한 후에 a = 321 라고 변경을 한다면 변수 a의 값은 321로 변경될 것이다. 하지만 처음에 할당했던 123이라는 데이터가 저장되어 있던 메모리의 주소 값에는 여전히 123이라는 값이 저장되어 있다. 다만 우리의 명령으로 변수가 참조하던 주소 값이 321의 주소로 바뀐 것이다. 이걸 재할당 했다고 표현한다.

변수의 반대 개념인 상수는 재할당이 불가능하여 값을 교체할 수가 없는 변수인 셈이다.

이렇게 변수에 재할당을 여러번 하다보면 아무 변수도 참조하지 않는 주소값들이 많이 생기게 되는데 그걸 정리하여주는 것이 garbage collector가 하는 일이다. Java, Python, JavaScript 같은 언어들은 가비지 콜렉터가 동작하여 이런 메모리들을 정리하여 준다.(C나 C++은 수동으로 개발자가 메모리 할당 해제들을 겸해야 되는 것과는 반대로) 상당히 편하지만 대신 메모리를 빡빡하게 최적화 하는 것은 힘들다 할 수 있다. 다음에 garbage collector에 대해서도 따로 다뤄볼 예정이다.

Call by Value

위에 원시 값은 Call by Value(원본 값이 복사되어 전달)를 따른다했는데 위의 예시를 보면 초기에는 myMoney와 yourMoney는 같은 값을 가지고 있었지만 myMoney에 2000원이 늘어난다고 해서 yourMoney까지는 변경되지 않는다. 왜냐하면 서로 다른 메모리상의 주소 값을 참조하고있고 그 안의 값만 복사하여 가져온 것이기 때문이다(yourMoney 변수가 참조하는 메모리 주소 값에 myMoney 변수가 참조하는 메모리 주소 값 내의 값을 복사하여 전달).

하지만 ECMAScript 사양에서 메모리를 어떻게 관리해야 하는지 명확하게 정의되어 있지 않다고 한다. 그래서 실제 JS엔진을 구현하는 브라우저 제조사에 따라 실제 내부동작은 차이가 있을 수 있다고 한다.🤨

중요한 점은 변수자체도 값의 메모리 주소를 기억한다는 점이다.

객체

객체는 프로퍼티의 개수가 제한되어 있지않고 값의 크기도 제약이 없음으로 복합적이며 복잡한 자료구조이다. 구현 방식도 브라우져 제조사에 따라 다를 수 있다한다. 원시 값은 적은 메모리 값을 소비하지만 객체는 상황에 따라 크기가 매우 클 수 있다.

V8 JS 엔진에서는 프로퍼티에 접근하는 성능을 보장하기 위해 동적 탐색 대신 히든 클래스라는 방식을 사용해 C++ 객체의 프로퍼티 접근 속도에 근접한 성능을 보장한다 한다.🧐 이 내용에 대해서도 추후에 살펴봐야 겠다.

위의 원시 값은 변경 불가능한 값이었지만 객체는 변경이 가능한 값이다. 그리하여 객체에 값을 변경하면 새로운 주소 값으로 참조가 변경되는 재할당이 아닌 주소 값 변경없이 값이 변경된다.

객체또한 원시 값처럼 변경불가능하게 한다면 신뢰성이 확보되겠지만 워낙 크기가 천차만별이라 메모리의 효율이 떨어질 위험이 높아 성능에 악영향을 끼칠 수 있어 변경 가능한 값으로 설계되었다고 한다.

이러한 특성때문에 객체는 여러 개의 식별자가 하나의 객체를 공유할 수 있다.

Call by Reference

이미지에서 yourCar를 myCar에 할당한 다음 myCar의 이름을 변경했는데 yourCar에도 반영되고, yourCar의 제조사명을 포르쉐로 넣어주었는데 myCar도 같이 변경된 것을 확인할 수 있다.

JS의 객체를 다른 변수에 할당해주면 이렇게 얉은 복사를 하게되는데, 그러면 서로 같은 메모리 공간을 참조하기 때문에 서로의 변동사항이 서로 반영된다. (두개의 식별자가 하나의 객체를 공유 중)

마무리

책에 따르면 JS에서 값에 의한 전달이나 참조에 의한 전달은 식별자가 기억하는 메모리 공간에 저장되어 있는 값(주소 값)을 복사해서 전달한다는 면에서 동일하다 한다. 또한 JS에는 포인터라는 개념이 없어 변수에 저장되어 있는 값이 원시 값이냐 참조 값이냐의 차이만 있을 뿐이고 그래서 정확히는 참조에 의한 전달은 존재하지않고 값에 의한 전달만이 존재한다고 한다.

포인터가 존재하는 C의 개념을 먼저 알고있다가 접하니 혼란스럽지만🤪 원시 값이던 객체던 할당할 값이 존재하는 주소값을 전달해주는 것에서 동일하고, 변경하게 될 시에 참조하는 주소값의 데이터가 원시 값이면 재할당을, 객체이면 해당 주소값의 값을 변경한다는 차이점을 설명하는 것 같다.

좀 더 JS와 친해지면서 더 자세히 학습해봐야겠다. 🧐

profile
ios 개발자를 목표로 성장중입니다 🧐

0개의 댓글