데보션앱 소개페이지 바로가기
로그인 선택

신고하기

CLOSE
신고사유 (대표 사유 1개)
상세내용 (선택)
0/200
  • 신고한 게시글은 더 이상 보이지 않습니다.
  • 이용약관과 운영정책에 따라 신고사유에 해당하는지 검토 후 조치됩니다.
  • 허위 신고인 경우, 신고자의 서비스 이용이 제한될 수 있으니 유의하시어 신중하게 신고해 주세요.
(이 회원이 작성한 모든 댓글과 커뮤니티 게시물이 보이지 않고, 알림도 오지 않습니다.)

미리보기

커뮤니티

      1,234

      badge 23.06.15

      글 등록

      카테고리를 선택해주세요.

      DEVOTEE를 활성화 시키면
      지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.

      버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.

      임시저장함에 저장되었습니다. 저장일시 : 2022.5.17 14:29:08

      임시저장함

      제목을 선택하시면 이어서 작성이 가능하며,
      최대 20건까지 저장합니다.
      컨텐츠 유형, 제목, 저장일시, 삭제로 이뤄진 임시저장 목록
      컨텐츠 유형 제목 저장일 삭제

      데보션 블로그 게재 요청

      CLOSE
      • *
      • *

      본인인증

      효율적인 데보션 서비스 이용 및
      고객님의 소중한 개인정보보호를 위해
      본인인증을 진행해주세요. 본인인증 미 진행 시 로그인이 제한됩니다.
      본인인증 실패

      본인인증 로그인에 실패하였습니다.
      회원이 아니시거나 본인인증 등록이
      완료되지 않은 사용자입니다.

      회원정보 연결

      [코어JS스터디] 1주차. JavaScript의 Data Type

      Teus 23.10.17
      355 1 0
      DEVOTEE 요약
      Teus는 RN 스터디 이후에 프론트엔드 개발자들과 함께 JavaScript의 동작 원리를 공부하기 위해 "코어 자바스크립트" 스터디를 시작했습니다. 본 스터디는 온라인과 오프라인 혼합으로 진행하며 데이터 타입에 초점을 맞추고 있습니다. 데이터 타입은 원시 타입과 참조 타입으로 분류되며, 원시 타입은 값 자체가 변하지 않는 불변성 데이터이고, 참조 타입은 메모리의 주소값을 복사하는 데이터입니다.

      안녕하세요. Teus입니다.


      기존 RN스터디 이후에 코어자바스크립트 스터디를 시작 했습니다!

      image.png


      기존 RN스터디를 진행한 스터디원들 대다수가 프론트앤드 개발자 였습니다.

      그래서 튼튼한 지식기반을 확보하기 위해서

      JavaScript의 동작 원리를 공부할 수 있는 코어자바스크립트(정재남) 를 가지고 스터디를 시작했습니다!

      이번 내용은 그 첫번째. 데이터 타입 입니다.


      0. 스터디 운영

      이번 스터디는

      지난주 내용 발표 -> 함께 독서 -> 정리

      의 순서로 진행합니다.

      때문에 효율적인 진행을 위해서 온라인으로 스터디를 진행하며

      종종 Offline으로 만나서 스터디를 진행할 예정입니다 🙃

      image.png


      1. Data Type의 종류

      데이터 타입은 primitive type, Reference type 크게 2가지고 나뉨.

      이때 구분은 아래처럼 됩니다.

      data type  +-> primitive type -> Number, String, Boolean, null, undefined, Symbol
                 | 
                 |
                 +-> Reference type -> Object - Array,Function, Date. RegExp, Map, Set

      일반적으로 두 type의 차이점이 아래처럼 알고 있죠?.

      Primitive : 불변성 Data이기 때문에 값 자체가 변하지 않는다.

      한번 생성된 원시타입의 메모리 공간은 값이 회수되어 초기화되기 전 까지 다른 값으로 변경되지 않는다 이를 불변성을 띈다고 표현한다

      Reference : 참조형 Data이기 때문에 메모리의 주솟값을 복사한다.

      하지만 실제 내부적으로는 그렇게 되지 않는데....


      2. Data Type에 대한 배경지식

      아래 코드를 보면

      var a = 20

      단순하게 변수 a는 20이라는 값을 가리킨다고 설명하나


      사실은

      1. 변수를 만든다.

      변수 선언(Variable Declaration)은 값을 저장하기 위한 메모리 공간을 확보하고 변수 이름과 확보된 메모리 공간의 주소를 연결해서 값을 저장할 수 있게 준비하는 과정입니다.

      1. 그 변수를 식별하기 위한 이름은 'a'이다.

      2. a가 가리키는 Data는 20이다

      데이터 할당(Data Allocation)은 데이터를 저장하기 위한 별도의 메모리 공간 다시 확보(데이터 영역)해서 데이터를 저장하고 그 주소를 변수 영역에 저장한다.

      의 순서로 동작합니다.


      변수(variable)와 식별자(identifier)를 혼용하는 경우가 많다.

      • 변수 : 변할 수 있는 수

        영어 단어 variable은 원래 '변할 수 있다'라는 형용사이지만 컴퓨터 용어로 쓸 때는 '변할 수 있는 무언가'라는 명사로 확장시켰다.

        여기서 '무언가'란 데이터를 말한다. 숫자, 문자열, 객체, 배열

      • 식별자 : 어떤 데이터를 식별하는 데 사용하는 이름. 즉, 변수명


      3. 변수 선언과 데이터 할당

      위에서 알아보았듯, 변수를 만들 때는 Data를 가리키는 식별자정보, 그리고 Data의 정보가 담기게 됩니다.

      이때 이 구조를 컴퓨터의 메모리 구조로보면 아래처럼 볼 수 있습니다.

      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003




      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      ...

      데이터



      20




      임의로 식별자 영역, 데이터 영역이라고 기술 하였지만

      여턴 식별자 정보를 저장하는 영역해 해당 식별자의 이름과 가리키는 위치값을 저장하고

      해당 위치값에 실제 데이터를 저장하게 됩니다.


      그래서 여기서 알 수 있는것은 primitive type역시 주소값을 저장한다는 점 입니다!

      🤔 이렇게 메모리 공간을 나누는 이유는?데이터 변환의 자유 + 메모리를 더욱 효율적으로 관리 하기 위한 고민의 결과이다.

      자바스크립트는 숫자형 데이터 64비트(8바이트)를 확보하지만, 문자열은 한 글자당 영어 1바이트, 한글 2바이트로 특별한 규격없이 전체 글자 수가 가변적으로 메모리 용량도 가변적이다.


      메모리 공간을 나누지 않고 변수 영역에 바로 실제 데이터를 저장한다면, 데이터 변환 시 '확보된 공간을 변한된 데이터 크기에 맞게 늘리는 작업'이 필요하다.

      해당 공간이 메모리 상의 마지막이라면 뒤쪽으로 늘리기만 하면 된다. 하지만 중간이라면 데이터를 옮기고, 식별자의 크기를 늘리는 작업으로 컴퓨터가 처리해야 할 연산이 많아진다.

      그래서 문자열 데이터의 변환을 처리하기 위해 변수와 데이터를 별도의 공간에 나누어 저장하는 것이 효율적이다.

      이때 식별자 a가 가리키는 변수값이 바뀔 경우, 아래처럼 변경이 발생 합니다.

      var a = 20
      a = 50
      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5004




      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      ...

      데이터



      20

      50



      기존(@5003) 데이터는 자신이 주소를 저장하는 변수가 하나도 없게 되면 가비지 컬렉터(garbage collector)의 수거 대상이 된다.

      JavaScript도 Data를 바라보는 Reference Count를 기반으로, Reference Count가 0이될 경우 해당 Data를 수거 대상이 되고,

      가비지 컬렉터는 런타임 환경에 따라 특정 시점이나 메모리 사용량이 포화 상태에 임박할 때마다 자동으로 수거 대상들을 수거한다.

      저 그럼 이 내용은 불변값으로 확장시켜 볼까요?


      4. 기본형 데이터와 참조형 데이터

      variable과 constant의 경우 단어에서 알 수 있듯 변할 수 있음 vs 변할 수 없음의 특징을 가지고 있습니다.

      ES6이후에 데이터의 불변성 이라는 내용을 많이 다루게 됩니다.


      이때 데이터의 불변성, 가변성과 variable, constant를 구분해서 이해할 필요성이 있습니다.

      variable과 constant : 식별자가 가리키는 값이 변경될 수 있냐 or 없냐 구분

      식별자 영역이 수정될 수 있냐의 여부

      데이터의 불변성 : 데이터 영역의 값이 변할 수 없다는 것을 의미

      데이터 영역에 한번 쓰여진 값을 사라질때까지 변하지 않음

      3장에서 다뤘던 코드를 예시로 보겠습니다.

      var a = 20
      a = 50

      위 코드를 보면, a = 20으로 만들어 진 이후 a = 50으로 값이 변합니다.

      식별자 a가 가리키는 값이 @5004메모리 주소로 바뀌었으므로 a는 변수입니다.

      이때 기존에 @5003위치에 있던 20이라는 값은 변하지 않았고 @5004위치에 새로운 값이 만들어 졌습니다.

      그렇기 때문에 식별자 a는 변수이고 a가 가리키는 data를 불변값 입니다.

      Primitive type의 data들은 데이터 영역에 Data가 바로 기록되기 때문에 불변값이 됩니다.


      4_1. 가변값(mutable)

      이때 Reference type의 data같은 경우는 조금 다르게 동작하게 됩니다.

      아래 코드르 보실까요?

      var a = {b : 20, c : 50}
      a.b = 220
      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003




      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      5006

      데이터



      @7001 ~ ?

      20

      50


      • a's object의 영역

      주소

      ...

      7002

      7003

      7004

      7005

      ...

      데이터



      식별자명 : b, 값 : @5004

      식별자명 : c, 값 : @5005



      mutable의 경우 위처럼 식별자가 처음 가리키는 Data영역 위치에 Data가 있는 것이 아니라, object의 위치를 가리키게 됩니다.

      그리고 그 object가 다시 Data영역을 가리키게 됩니다.

      그래서 이때 a.b의 값을 변경하면 아래처럼 바뀌게 됩니다.

      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003




      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      5006

      데이터



      @7001 ~ ?

      20

      50

      220

      • a's object의 영역

      주소

      ...

      7002

      7003

      7004

      7005

      ...

      데이터



      식별자명 : b, 값 : @5004

      식별자명 : c, 값 : @5005



      이제 mutable과 immutable의 차이점이 보이시나요?

      Object 객체를 불변성으로 사용하기 위해서는 아래와 같은 방법을 고려해볼 수 있음

      설정에 따라 불가능한 경우 : Object.defineProperty, Object.freeze 등


      4_2. 변수의 복사

      위를 통해서 mutable과 immutable의 차이점을 볼 수 있었을 겁니다.

      이제 변수의 복사를 할 때 얕은복사와 깊은복사를 이해할 수 있습니다.


      내용을 정리하기 전에 얕을복사와 깊은복사를 비교해보면

      • 얕은복사 : 단순하게 식별자가 가리키는 값을 다른 식별자에 복사해 주는것을 의미

      바로 아래 단계의 값만 복사하는 방법(Data영역에 있는 값만 복사)

      (a와 copy_a가 종속적임)

      • 깊은복사 : 식별자가 가리키는 값이 주소값일 경우, 재귀적으로 데이터가 존재하는 위치까지 가서 데이터를 복사해옴

      내부의 모든 값들을 하나하나 전부 복사

      (a와 copy_a가 완전 독립되어있음)


      4_2_1. immutable의 변수 복사

      먼저 immutable일 경우를 보겠습니다.

      var a = 20
      copy_a = a
      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003

      식별자명 : copy_a, 값 : @5003



      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      ...

      데이터



      20




      불변형은 식별자의 값 이 가리키는부분에 바로 Data가 있습니다.

      때문에 얕은복사나 깊은복사나 차이점이 없습니다.


      이때 copy_a = 30을 실행하면 아래처럼 작동하게 되겠죠

      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003

      식별자명 : copy_a, 값 : @5004



      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      ...

      데이터



      20

      30



      @5003위치의 값이 바뀌는 것이 아니라, 다른 위치에 Data를 만들고, 이 메모리주소를 copy_a가 가지고오게 됩니다.


      4_2_2. mutable의 변수 복사

      반면 mutable의 경우를 볼까요?

      var a = {b : 20, c : 50}
      var copy_a = a
      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003

      식별자명 : copy_a, 값 : @5003



      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      5006

      데이터



      @7001 ~ ?

      20

      50


      • a's object의 영역

      주소

      ...

      7002

      7003

      7004

      7005

      ...

      데이터



      식별자명 : b, 값 : @5004

      식별자명 : c, 값 : @5005



      이 상태에서 object의 값에 접근하는 순서를 보면

      a.b: @5003 -> @7003 -> @5004 -> 20

      a_copy.b: @5003 -> @7003 -> @5004 -> 20


      때문에, a.b의 값을 바꿀 경우 a_copy.b의 값 역시 바뀌게 됩니다.

      (@7003위치가 가리키는 값이 바뀌기 때문에)

      a.b = 220
      //==copy_a.b = 220
      • 식별자 영역

      주소

      ...

      1002

      1003

      1004

      1005

      ...

      데이터



      식별자명 : a, 값 : @5003

      식별자명 : copy_a, 값 : @5003



      • 데이터 영역

      주소

      ...

      5002

      5003

      5004

      5005

      5006

      데이터



      @7001 ~ ?

      20

      50

      220

      • a's object의 영역

      주소

      ...

      7002

      7003

      7004

      7005

      ...

      데이터



      식별자명 : b, 값 : @5006

      식별자명 : c, 값 : @5005



      때문에 mutable의 경우 변수의 깊은복사와 얕은복사가 달라지게 됩니다.

      (깊은복사를 하는 방법은 다음챕터에서 다룹니다.)


      5. Immutable object

      Primitive Type의 object는 기본적으로 Immutable object입니다.

      하지만 Reference Type Data역시 Immutable object처럼 복사를 하는것이 가능합니다.

      1. immutable.js, immer.js와같은 user-defined package를 사용하거나

      2. ES6의 spread연산자를 사용해서 구현할 수 있습니다.

      결국 mutable object의 깊은복사는

      mutable object를 복사할 때 Immutable object처럼 a와 copy_a가 독립적인 object를 만드는 것입니다.

      코어자바스크립트 책에서는 재귀함수를 통해서 Object type의 깊은복사를 구현하는 방법은 아래와 같습니다.

      const copy_func = function(target) {
          var result = {}
          if (typeof target === "object" && target !== null){
              for (var prop in target){
                  result[prop] = copy_func(target[prop]);
              }
          } else {
              result = target
          } return result
      }

      재귀함수를 통해서 value가 Object type일 경우 다시금 반복적으로 copy_func를 수행합니다.

      결국 깊은복하는 동일한 Data를 같는 새로운 object를 만들어 내는 작업 입니다.

      또는 Object type의 경우 Json과 그 구조가 동일하기 때문에 JSON object를 사용해서 깊은복사를 할 수 있습니다.

      const copy_func_json = function(target) {
          return JSON.parse(JSON.stringify(target));
      }


      6. null과 undefined

      다른 Programming 언어를 사용 하다가 JavaScript에서 사용자를 당황시키는 친구들 입니다.

      null : 값 자체가 없음

      undefined : 정의되어있지 않음

      undefined 는 값이 없음을 나타내는 값 (데이터 영역에 undefined가 있다) null 은 변수가 참조할 데이터 영역의 주소가 없음을 나타낸다

      분명 한글로 풀어 써도 큰 차이점이 없습니다.


      책에는 긴 설명이 되어있으나, undefined는 JavaScript Engine에서 만들어내는 값으로

      1. 값을 대입하지 않은 변수, 즉 데이터 영역의 메로리 주소를 지정하지 않은 식별자에 접근할 때

        var a; console.log(a)

      2. object내부의 좋재하지 않는 property에 접근하려고 할 때

        var a = {b : 20}; console.log(a.c)

      3. return문이 없거나 호출되지 않는 함수의 실행 결과

        var a = () => {b = 20};console.log(a())

      '비어있음'을 명시적으로 나타내고 싶을 때는 undefined가 아닌 null을 쓰는 것을 권장한다.

      (sw : undefined 는 연산은 되지 않지만 에러를 발생시키지 않기 때문에 사용자는 값이 없음을 나타낼 때 null 을 사용하여 명확하게 문제를 해결하고 넘어가는 편이 좋을 것 같다)

      주의할 점자바스크립트 자체 버그type null === 'object'

      위처럼 깔끔하게 정리되면 좋겠지만

      문제는 이 외에 아래처럼 Array를 생성했을때 마주하게 됩니다.

      var a = Array(3)
      console.log(a)
      //>>[empty * 3]

      위 코드의 경우 크기가 3인 Array를 만듭니다.

      문제는 이 Array의 3개의 공간에는 undefined가 할당되는것이 아니라 아예 비어있는 상태, empty 입니다.

      반복문을 동작할 때 undefined와 empty는 다른 동작을 보여줍니다.

      var arr1 = [undefined, 1];
      var arr2 = [];
      arr2[1] = 1;
      
      arr1.forEach(function (v, i) {
        console.log(v, i);
      }); // undefined 0 / 1 1
      arr2.forEach(function (v, i) {
        console.log(v, i);
      }); // 1 1
      
      arr1.map(function (v, i) {
        return v + i;
      }); // [NaN, 2]
      arr2.map(function (v, i) {
        return v + i;
      }); // [empty, 2]
      
      arr1.filter(function (v) {
        return !v;
      }); // [undefined]
      arr2.filter(function (v) {
        return !v;
      }); // []
      
      arr1.reduce(function (p, c, i) {
        return p + c + i;
      }); // undefined011
      arr2.reduce(function (p, c, i) {
        return p + c + i;
      }); // 11

      그래서 JavaScript를 사용할 경우, 내가 사용할 Array object가 undefined상태인지, empty상태인지를 꼭 확인해야 합니다.

      댓글 0

      DEVOTEE를 활성화 시키면
      지금 작성한 댓글에 AI가 댓글을 달아줍니다.

      Teus 님의 최신 블로그

      더보기
      동영상 기고하기