2020-12-10 JS 데이터타입과 변수저장방식

데이터타입

  • Primitive : number, string, boolean, null, undefined, symbol => 기본형은 메모리 스택영역에 값이 함께 할당되고 연산시 복제된다.

  • reference : object, array, function, date, regex가 있다. Map, WeakMap, Set 등은 Object의 하위개념이다. => 참조형은 주소값이 저장된다. 참조형 객체들을 복사하면 값이 복사되는게 아닌 주소값이 복사된다.

  • JS에서는 Number에서 8바이트를 확보한다. 이렇게 확보하는 이유는 과거에 비해 메모리가 넉넉해졌기 때문이다.

  • 변수와 식별자. 변수는 변할 수 있는 값을 의미하고 식별자는 변수의 이름을 지칭한다.

    • const identifier = "hello world";
      let tmp = 1;
      tmp = "1";
      
    • 위의 코드처럼 tmp, identifier는 값을 구별할 수 있는 식별자이고, 안에 있는 데이터는 변수라고 이야기한다.

    • 데이터의 변화에 대해 효율적으로 관리하기 위해 변수영역과 데이터영역을 따로 분리한다. identifier, tmp는 변수영역의 특정 주소값에 저장되고, 각각의 값들은 데이터영역의 주소값이 저장된다.

    • String의 경우 영어, 한글이냐에 따라 각각 1바이트, 2바이트로 구분되고 전체글자수와 필요한 메모리양이 다르기 때문에 데이터영역, 변수영역으로 분리를 해야 가변적으로 대응이 가능하다.
  • 불변과 상수 : 변수와 상수를 구분 짓는 대상은 변수영역의 메모리다. 한번 데이터할당이 이루어진 다시 데이터를 재할당 여부이고, 불변은 데이터영역의 메모리를 구분한다. 기본값들은 모두 불변이다.

    • 변수가 가변하다는건 변수영역의 데이터 주소값이 달라질 수 있다는 의미이다.
  • 참조형 : 참조형은 기본값과 달리 객체의 프로퍼티 영역이 별도로 존재한다.

    • let obj {
        number: 1,
        tmp : "tmp"
      };
      
    • 위와 같은 obj가 있다고 가정하자. 변수 obj는 변수영역의 특정 주소에 저장되고, 값은 데이터영역의 특정주소값이 매핑이 된다. 하지만 프로퍼티들이 존재하기 때문에 데이터 영역의 특정주소가 매핑되는건, @새로운주소값~?까지 각 프로퍼티들에 대한 주소값을 가지게 된다.

    • 만약 number에 대한 주소값이 4000이고 tmp에 대한 주소값이 4001라고 하면, 변수영역의 4000과 4001은 1, “tmp”를 가지고 있는 주소값을 찾아서 저장하고 없으면 데이터영역에 1, tmp를 새로 할당하여 저장한다.
  • 데이터에 의해 자신의 주소를 참조하는 변수 갯수를 참조카운트라고 정의한다. 참조카운트가 0이면 GC의 대상이된다.

  • 변수의 복사

    • let a = 10;
      let b = a;
      
      let obj1 = {c : 10, d: 'hello'}
      obj2 = obj1;
      
      b = 20;
      obj2.c = 30;
      
      // 해결하기
      obj2 = {c: 30, d: 'hello'}
      
    • 주소 1001 1002 1003 1004 1005
      데이터 name : a
      value: @5001
      name:b
      value: @5004
      name: obj1
      value: @5002
      name: obj2
      value: @5002
       
      주소 5001 5002 5003 5004 5005
      데이터 10 @7103~? ‘hello’ 20 30
      주소 7103 7104      
      데이터 name: c
      value: @5005
      name: d
      value: @5003
           

      b에 있는 값을 20으로 할당할때, 데이터영역에서 20이 있는지 확인하고 있으면 20에 해당하는 주소값 @5004를 할당한다. 없으면 데이터영역의 새로운 주소에 값을 할당

    • obj2.c를 변경할때 문제가 발생한다. obj는 변수영역의 1002주소값에 저장되어있고 값은 5002에 저장되어있다. 5002를 보면 @7103~?까지 참조를 하고 있고, 프로퍼티 c는 7103에 저장되어있고 @5004에 값이 할당되어있다. 30으로 변경하면 @5005로 변경한다. 하지만 obj1 역시도 @5002를 참조하고 있고, @5002에서 7103~으로 바라보고 있기때문에 obj1.c도 30으로 변한다. 이게 가장 큰 차이다.

    • 기본형도 참조형도 모두다 주소값을 복하한다. 하지만 기본형은 주소값을 1번만 복사하고, 참조형은 단계가 더 있어서 이런 상황이 발생한다.

    • 마지막줄에 있는 코드처럼 재할당을 하면 위의 이슈가 해결된다.
  • 얕은 복사는 바로 아래단계 값만 복사하고 깊은복사는 내부의 모든 값을 복사한다. JS의 copyObject는 얕은복사만 수행. 이런경우 nestedObject에서 복사할때 주소값만 복사하기 때문에 원본 사본이 모두 동일한 주소값을 가리키게 된다.

    • let user = {
        name: 'jimmy',
        assets: {
          facebook: 200,
          google: 1000,
          apt: "apt"
        }
      }
      
      let user2 = copyObject(user);
      user2.name = 'test';
      user.name === user2.name => false;
      
      user.assets.facebook = 10000;
      user.assets.facebook === user2.assets.facebook => true
      
    • 복제한 객체에 대한 변경 이슈를 해결하기 위해서는 내부적으로 모두 복사하는 깊은복사가 필요하다.
  • JS에서 undefined를 리턴하는 경우

    • 값을 할당하지 않은 변수
    • 객체 내부에 존재하지 않는 프로퍼티에 접근할때
    • return이 없거나 호출되지 않는 함수의 실행결과
  • null은 typeof가 object => JS버그

Written on December 10, 2020