Eun_Frontend
  • [코디테스트 공부] - JavaScript Array.fill()의 함정 (참조 타입과 원시 타입의 차이)
    2025년 02월 05일 16시 17분 05초에 업로드 된 글입니다.
    작성자: 동혁이

     

    JavaScript Array.fill()의 함정 (참조 타입과 원시 타입의 차이)

     

     

    작성 배경

    DFS, BFS와 같은 그래프 알고리즘을 구현하면서 2차원 배열을 만들어 초기화하는 경우가 많습니다.

    특히 인접 리스트를 만들거나 방문(boolean) 배열을 초기화할 때 충분히 만날 수 있는 문제라고 생각합니다. (그게 바로 저..)

     

     

    사전 지식

    JavaScript에서 데이터 타입은 크게 두 가지로 나뉠 수 있습니다.

    1. 원시 타입
    - Number, String, Boolean, null, undefined 등
    - 값 자체가 복사됨
    
    2. 참조 타입
    - Object, Array 등
    - 메모리 주소가 복사됨

     

    예시 코드

    // 1. 원시 타입 예시
    const 원시타입배열 = new Array(3).fill(false);
    원시타입배열[0] = true;
    console.log(원시타입배열);
    // 출력: [true, false, false]
    
    
    // 2. 참조 타입 예시
    const 참조타입배열 = new Array(3).fill([]);
    참조타입배열[0].push(1);
    console.log(참조타입배열);
    // 출력: [[1], [1], [1]]
    
    
    // 3. 객체로 보는 더 명확한 예시
    const 객체배열 = new Array(3).fill({ count: 0 });
    객체배열[0].count = 1;
    console.log(객체배열);
    // 출력: [{ count: 1 }, { count: 1 }, { count: 1 }]

     

    혹시 위 예시 코드를 보고 감이 오시는 분은 굳이 아래까지 안읽으셔도 좋을 것 같습니다!!

     

    여기서 이해가 안되시는 분들이 있기 때문에

    메모리 주소를 이용한 예시를 보겠습니다.

    // 원시 타입의 경우
    const primitive = new Array(3).fill(false);
    /*
    메모리:
    [false] <- primitive[0]
    [false] <- primitive[1]
    [false] <- primitive[2]
    */
    
    
    // 참조 타입의 경우
    const reference = new Array(3).fill([]);
    /*
    메모리: [](배열) <- 주소1234
    [주소1234] <- reference[0]
    [주소1234] <- reference[1]
    [주소1234] <- reference[2]
    */

     

     

    해결 방법

    // 1. map과 화살표 함수 사용
    const correct1 = new Array(3).fill(0).map(() => []);
    
    // 2. Array.from 사용
    const correct2 = Array.from({ length: 3 }, () => []);
    
    // 3. 반복문 사용

     

     

    실제 알고리즘에서 활용 예시

    예를 들어, 그래프를 표현하는 인접 리스트를 만들때

    // 잘못된 방법
    const graph1 = new Array(5).fill([]); // 모든 정점이 같은 배열을 공유
    
    // 올바른 방법
    const graph2 = new Array(5).fill(0).map(() => []); // 각 정점이 독립적인 배열을 가짐
    
    // 차이점 확인
    graph1[0].push(1);
    graph2[0].push(1);
    
    console.log('잘못된 방법:', graph1);
    // 출력: [[1], [1], [1], [1], [1]]
    
    console.log('올바른 방법:', graph2);
    // 출력: [[1], [], [], [], []]

     

     

    결론

    fill() 메서드를 사용할 때는 원시 타입과 참조 타입의 차이를 반드시 이해해야 한다는 것을 코딩 테스트 문제를 풀면서 다시 한 번 이해를 하게되었습니다.

    2차원 배열이나 객체 배열을 초기화할 때는 map()이나 Array.from()을 사용하여 각 요소가 독립적인 참조를 가지도록 해야 합니다.

     

    이렇게 게시글을 작성해서 이 글을 읽고 계신 분들은 JavaScript의 참조 타입과 원시 타입의 차이를 이해하고, 실제 코딩 테스트나 프로젝트에서 이 지식을 활용 했으면 좋겠습니다!!

    댓글