목차

    JS의 자료형(Data Types)

    최신 ECMAScript에 따르면, JS의 **자료형(Data type)**은 크게 9개로 분류된다

    Primitives(원시형)

    typeof instance(값) 로 출력되는 값이 아래 중 하나에 해당하는 자료형

    1. number
    2. string
    3. boolean
    4. bigint
    5. symbol
    6. undefined

    Structural Types(구조형)

    typeof instance(값) 로 출력되는 값이 아래 중 하나에 해당하는 자료형

    1. object
      • 일반적인 객체({...} or new Object)와, new 키워드로 만들어진 모든 data를 포함
      • array literal([ ])로 만들어진 배열(array)도 object임
    2. function

    Structural Root Primitive

    typeof instance(값) 로 출력되는 값이 "null"인 자료형

    1. null
      • null은 크게 보면 primitive type에 해당되지만, typeof 연산자로 확인해보면 "object"가 출력됨

    불변성(Immutability)에 따른 자료형(Data Type)의 분류

    위 9가지 자료형을 Memory에서 data가 변경할 될 수 없는 것(Immutable)과 변경될 수 있는 것(Mutable)로 다시 분류할 수 있다.

    위 자료형 중 오직 object만이 Mutable하며, 나머지 자료형은 모두 Immutable하다.

    immutable한 값들을 Primitive values라고 부른다

    Immutable values(Primitive values)

    한번 생성되어 메모리에 올라간 값이 수정되지 않는 값들을 의미한다.

    js 기준 9가지 자료형 중 "object"를 제외한 모든 자료형이 Immutable한 특징을 가진다.

    예시

    js에서, primivite values는 call by value로 호출된다

    let game = 'lol' let newGame = game

    즉, 위 코드의 상황을 그림으로 나타내면 아래와 같다

    위 코드를, 아래와 같이 변경해보자 .

    let game = 'lol'
    let newGame = game
    
    game = 'starcraft'

    그림으로 나타내보자.

    실제로 로그를 찍어보면, game = 'starcraft'를, newGame = 'lol'을 출력할 것이다.

    위와 같은 결과가 나오는 이유는, string 자료형은 그 값이 메모리에서 변하지 않는(Immutable)한 자료형이기 때문이다.

    immutable한 자료에 대한 할당은 'deep copy'를 한다.

    그렇다면, mutable한 자료형의 예시도 살펴보자

    Mutable values(Objects)

    object 예시

    let garen = { role: "person" }
    let ani = garen

    위 코드를 그림으로 나타내면 아래와 같다

    하지만, object의 가변성을 고려하지 않고 object의 value 값을 아래와 같이 수정해보자.

    let garen = { role: "person" }
    let ani = garen
    
    garen.role = "warrior"

    위 상황을 그림으로 나타내면 아래와 같다

    그리고 그 결과는 아래와 같을 것이다.

    console.log(garen.role) // 'warrior'
    console.log(ani.role) // 'warrior'
    console.log(garen === ani) // true

    프로그래머의 의도가 garen과 ani의 role을 한번에 "warrior"로 바꾸고자 했다면 위 방식으로 해도 문제가 되지 않을 수 있다.

    하지만 일반적인 경우라면 garen과 ani의 role이 한번에 바뀌는 것을 원하지는 않을 것이다.

    object > array 예시

    let teamA = []
    let teamB = teamA

    위와 같은 상황에서, teamA에만 player1을 추가하기 위해 mutablility를 고려하지 않고 코딩하면 teamA뿐 아니라 teamB에도 플레이어가 추가되어 버린다.

    let teamA = []
    let teamB = teamA
    
    teamA.push("palyer1")

    mutable한 자료를 할당할 경우, 'shallow copy'가 된다.

    위와 같이 객체의 side effect를 예방하기 위해서,

    1. 객채의 가변성(mutability)을 이해해야 하고,
    2. 객체의 value를 변경할 때는 immutable한 방식으로 코딩하는 습관을 들이는 것이 중요하다

    Immutable하게 Objects의 value 변경하기

    (mutable variable을 deep copy하기)

    immutable하게 객체의 값을 변경하기 위해선, object literal( { } or [ ] ) 또는 new 키워드 등을 통해 새로운 객체를 선언한 뒤, spread operator(...)로 이전 객체의 값을 복사하여 사용하는 방법을 사용할 수 있다.

    배열의 경우, map()과 같은 새로운 배열을 return하는 내장 method를 사용할 수도 있다.

    object 예시

    let garen = { role: "person" }
    let ani = garen
    
    garen = {...garen, role: 'warrior'}

    object > array 예시

    let teamA = []
    let teamB = teamA
    
    teamA = [...teamA, 'player1']

    불변성 관리 lib(immer 등)이 필요한 이유

    위처럼 간단한 구조의 객체라면, 불변성 관리를 위해 단순히 전개연산자 정도만 사용해주면 된다.

    하지만 만약 객체의 depth가 깊고, 깊은 depth의 값을 변경해야 한다면 어떻게 해야할까?

    const complicatedObj = {
      a: {
        b: {
          c: {
            num: 1
          }
        }
      }
    }
    
    // 이렇게 복잡하게 해야 한다
    const editedObj = {
      ...complicatedObj,
      a: {
        ...complicatedObj.a,
        b: {
          ...complicatedObj.a.b,
          c: {
            ...complicatedObj.a.b.c,
            num: 500
          }
        }
      }
    }

    즉, 불변성 관리 lib는 사용하고 있는 객체가 복잡한 형식일 때 사용하면 매우 손쉽게 불변성 관리를 할 수 있기에 사용한다. (객체의 형식이 간단할 땐 굳이 사용할 필요 없음)

    immer 등의 불변성 관리 lib는 나중에 내가 필요할 때 써보고 포스팅 할 예정!

    'const'와 immutable

    다들 알다시피 'const'로 선언한 변수는 변수에 값을 재선언 및 재할당이 불가능하다.

    하지만 변경이 불가능한 것은 const 변수의 "값"이지, const 변수가 참조하고 있는 자료의 값은 아님을 이해하는 것이 중요하다

    const 변수의 값인 "주소" 변경 시도 → 에러

    const garen = {
    	role: 'person'
    }
    
    garen = {
    	role: 'warrior'
    } // Uncaught TypeError: Assignment to constant variable.

    const 변수의 값인 주소가 참조하고 있는 value 변경 → 정상작동

    const garen = {
    	role: 'person'
    }
    
    garen.role = 'warrior'

    참고

    JavaScript data types and data structures - JavaScript | MDN

    자바스크립트에서 불변성(Immutability)이란

    + Recent posts