만두의 부트캠프 🤔
  • 9-1. [JavaScript] 자료형, 복사
    2023년 10월 27일 12시 03분 04초에 업로드 된 글입니다.
    작성자: 만두33

     

     

    원시 타입과 참조 타입

     

    자료형(type) : 값(value)의 종류
    원시 타입 (primitive type)   참조 타입 (reference type)
    number, string, boolean, undefined, null, symbol   원시 자료형이 아닌 모든 자료형
    (배열, 객체,함수 ...)
    * 원시 자료형을 변수에 할당시 메모리 공간에 값 자체가 저장
    * 원시 값을 갖는 변수를 다른 변수에 할당시 원시 값 자체가 복사후 전달
    * 원시 자료형은 변경 불가능한 값(immutable value)
    즉, 한 번 생성된 원시 자료형은 읽기 전용(read only) 값
    특징 * 참조 자료형을 변수에 할당하면 메모리 공간에 주소값이 저장
    * 참조 값을 갖는 변수를 다른 변수에 할당시 주소값이 복사후 전달
    * 참조 자료형은 변경이 가능한 값(mutable value)

     

     

    JavaScript는 특별한 저장 공간에 참조 자료형을 저장한 후, 그 저장공간을 참조할 수 있는 주소값을 변수에 저장합니다.

    이때 참조 자료형을 저장하는 특별한 저장 공간을 힙(heap)이라고 부르기도 합니다.

    따라서 변수 arr에 해당하는 저장공간에는 주소값이 저장되어 있고, 그 주소값을 통해 참조 자료형에 접근할 수 있습니다.

    이를 참조한다(refer)고 합니다.

     

    원시 자료형은 원본(num)에 다른 값을 재할당해도 복사본(copiedNum)에 영향을 미치지 않습니다.

    반면에 참조 자료형은 원본(arr)을 변경하면 복사본(copiedArr)도 영향을 받는 것을 확인할 수 있었습니다.

    값 자체를 복사하는 원시 자료형과는 달리, 참조 자료형을 할당한 변수를 다른 변수에 할당할 경우 같은 주소를 참조하고 있기 때문입니다.

    참조 자료형을 변수에 할당하면 특정 저장 공간(heap)에 참조 자료형을 저장하고 그 공간의 주소를 변수에 저장한다.

     

     


     

    배열 복사하기

     

    • 원시 자료형이 할당된 변수를 다른 변수에 할당하면 값 자체의 복사가 일어난다. 따라서 원본과 복사본 중 하나를 변경해도 다른 하나에 영향을 미치지 않는다.
    • 참조 자료형이 할당된 변수를 다른 변수에 할당하면 주소가 복사되어 원본과 복사본이 같은 주소를 참조한다.
    • 참조 자료형의 주소값을 복사한 변수에 요소를 추가하면 같은 주소를 참조하고 있는 원본에도 영향을 미친다.
    • 참조 자료형이 저장된 변수를 다른 변수에 할당할 경우, 두 변수는 같은 주소를 참조하고 있을 뿐 값 자체가 복사되었다고 볼 수 없다.

     

    배열 복사 방법

    1. 배열 내장 메서드인 slice() 사용
    2. spread문법을 사용

     

    Slice()로 복사하기

    let arr = [0, 1, 2, 3];
    let copiedArr = arr.slice();
    console.log(copiedArr); // [0, 1, 2, 3]
    console.log(arr === copiedArr); // false

     

    spread syntax로 복사하기

    ... + 변수명 으로 배열을 펼칠 수 있다.

    let arr = [0, 1, 2, 3];
    
    console.log(...arr); // 0 1 2 3

     


     

    객체 복사하기

     

    Object.assign()

    객체를 복사하기 위해서는 Object.assign()을 사용한다.

    let obj = { firstName: "mandoo", lastName: "an" };
    let copiedObj = Object.assign({}, obj);
    
    console.log(copiedObj) // { firstName: "mandoo", lastName: "an" }
    console.log(obj === copiedObj) // false

     

     

     


     

    얕은복사

     

    spread syntax는 배열뿐만 아니라 객체를 복사할 때도 사용할 수 있습니다.

     

    let obj = { firstName: "mandoo", lastName: "an" };
    let copiedObj = {...obj};
    
    console.log(copiedObj) // { firstName: "mandoo", lastName: "an" }
    console.log(obj === copiedObj) // false

     

     

    slice(), Object.assign(), spread syntax 등의 방법으로 참조 자료형을 복사하면, 참조 자료형 내부에 중첩된 참조 자료형의 구조 중 한 단계까지만 복사합니다. 

    이것을 얕은 복사(shallow copy)라고 합니다.

     

     

     


     

    깊은복사

     

    JSON.stringify()와 JSON.parse()


    JSON.stringify()는 참조 자료형을 문자열 형태로 변환하여 반환

    JSON.parse()는 문자열의 형태를 객체로 변환하여 반환

     

     

    사용예시 = JSON.parse(JSON.stringify( ))

        ① 먼저 중첩된 참조 자료형을 JSON.stringify()를 사용하여 문자열의 형태로 변환

        ② 반환된 값에 다시 JSON.parse()를 사용

        ③ 깊은 복사와 같은 결과물을 반환

     

    const arr = [1, 2, [3, 4]];
    const copiedArr = JSON.parse(JSON.stringify(arr));
    
    console.log(arr); // [1, 2, [3, 4]]
    console.log(copiedArr); // [1, 2, [3, 4]]
    console.log(arr === copiedArr) // false
    console.log(arr[2] === copiedArr[2]) // false

     

     

    깊은 복사의 예외) 대표적인 예로 중첩된 참조 자료형 중에 함수가 포함되어 있을 경우 위 방법을 사용하면 함수가 null로 바뀌게 됩니다. 

     

    const arr = [1, 2, [3, function(){ console.log('hello world')}]];
    const copiedArr = JSON.parse(JSON.stringify(arr));
    
    console.log(arr); // [1, 2, [3, function(){ console.log('hello world')}]]
    console.log(copiedArr); // [1, 2, [3, null]]
    console.log(arr === copiedArr) // false
    console.log(arr[2] === copiedArr[2]) // false

     

     


     

    외부 라이브러리 사용


    완전한 깊은 복사를 반드시 해야 하는 경우라면, node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 설치하면 됩니다. 

     

    const lodash = require('lodash');
    
    const arr = [1, 2, [3, 4]];
    const copiedArr = lodash.cloneDeep(arr);
    
    console.log(arr); // [1, 2, [3, 4]]
    console.log(copiedArr); // [1, 2, [3, 4]]
    console.log(arr === copiedArr) // false
    console.log(arr[2] === copiedArr[2]) // false

     

     


    정리

    • 배열의 경우 slice() 메서드 또는 spread syntax 등의 방법으로 복사할 수 있다.
    • 객체의 경우 Object.assign() 또는 spread syntax 등의 방법으로 복사할 수 있다.
    • 위 방법으로 참조 자료형을 복사할 경우, 중첩된 구조 중 한 단계까지만 복사된다. (얕은 복사)
    • JavaScript 내부적으로는 중첩된 구조 전체를 복사하는 깊은 복사를 구현할 수 없다. 단, 다른 문법을 응용하여 같은 결과물을 만들 수 있다.
    • 대표적인 JSON.stringify()와 JSON.parse()를 사용하는 방법이 있지만, 예외의 케이스가 존재한다. (참조 자료형 내부에 함수가 있는 경우)
    • 완전한 깊은 복사를 반드시 해야 하는 경우, node.js 환경에서 외부 라이브러리인 lodash, 또는 ramda를 사용하면 된다.

     

     

     

     

     

    끝 😎

    '💻 코드스테이츠 x 경남abclab > Section 1' 카테고리의 다른 글

    11. DOM  (1) 2023.11.01
    10-2. [JavaScript] JavaScript Koans  (0) 2023.10.30
    9-2. [JavaScript] 스코프  (1) 2023.10.27
    8-2. [JavaScript] 객체  (1) 2023.10.26
    8-1. [JavaScript] 배열  (0) 2023.10.25
    댓글