본문 바로가기
JavaScript

원시/참조 자료형, 얕은복사 깊은복사

by lvd-hy 2023. 3. 6.
반응형

  • 자료형
    • 원시 자료형 (primitive data type)
      • number, string, boolean, undefined, null, symbol
      • 변수에 할당 시 메모리 공간에 값 자체가 저장
      • 원시 값을 갖는 변수를 다른 변수에 할당 시 원시 값 자체가 복사되어 전달
      • 변수에 할당한 값이 변경되었다면, 기존 값은 자동으로 메모리에서 삭제 (=가비지 컬렉터, garbage collector)
      • 윈시 자료형은 변경 불가능한 값(immutable value), 한 번 생성된 원시 자료형은 읽기 전용 (read only)ex.
      • let str = 'code'; str = 'states'; str[5] = 'z'; // s를 z로 변경 시도했으나 String은 원시자료형이므로 변경이 안됨 console.log(str); // 'states' 출력
    • 참조 자료형 (reference data type)
      • 배열(array), 객체(object), 함수(function)
      • 변수에 할당 시 메모리 공간에 주솟값 저장
      • 참조 값을 갖는 변수를 다른 변수에 할당 시 주솟값이 복사되어 전달
      • 참조 자료형은 변경이 가능한 값(mutable value)ex.
      • let arr=[0,1,2,3] arr[3] = '3'; // 3번 째 인덱스에 '3' arr.push(4); // 마지막 값에 4 삽입 arr.shift(); // 맨 앞 값 제거 console.log(arr); // [1,2,'3',4] 출력
  • 얕은 복사와 깊은 복사
    • 배열 복사하기
      • slice() : 배열 내장 메서드인 slice()를 사용하면 원본 배열을 복사
        let arr = [0, 1, 2, 3];
        let copiedArr = arr.slice();
        console.log(copiedArr); // [0, 1, 2, 3]
        console.log(arr === copiedArr); 
        // false 출력, copiedArr에 새로운 주소값이 생김
      • spread syntax (ES6)
        • 배열이 할당된 변수명 앞에 ... 을 붙여주면 배열의 각 요소를 확인할 수 있음
          let arr = [0, 1, 2, 3];
          console.log(arr); // [0, 1, 2, 3]
          console.log(...arr); // 0 1 2 3
          
          // 같은 요소를 가진 배열을 두 개 만든 후 변수에 각 할당 시, 다른 주소 참조
          let num = [1, 2, 3];
          let int = [1, 2, 3];
          
          console.log(num === int) // false
          
          // 배열의 각 요소를 펼쳐서 전달해도 다른 주소이기 때문에 false
          let arr = [0, 1, 2, 3];
          let copiedArr = [...arr];
          console.log(copiedArr); // [0, 1, 2, 3]
          console.log(arr === copiedArr); // false
          
          copiedArr.push(4);
          console.log(copiedArr); // [0, 1, 2, 3, 4]
          console.log(arr); // [0, 1, 2, 3]
      • 객체 복사하기
        • Object.assign()
          let obj = { firstName: "coding", lastName: "kim" };
          let copiedObj = Object.assign({}, obj);
          
          console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
          // 주소값이 다름
          console.log(obj === copiedObj) // false
        • spread syntax (ES6)
          • 배열 뿐 아니라 객체도 복사 가능
            let obj = { firstName: "coding", lastName: "kim" };
            let copiedObj = {...obj};
            
            console.log(copiedObj) // { firstName: "coding", lastName: "kim" }
            console.log(obj === copiedObj) // false
      • 얕은 복사 : 중첩된 구조 중 한 단계까지만 복사
        • slice() , Object.assign() , spread syntax 등의 방법으로 참조 자료형을 복사했을 때
          let users = [
          	{
          		name: "kimcoding",
          		age: 26,
          		job: "student"
          	},
          	{
          		name: "parkhacker",
          		age: 29,
          		job: "web designer"
          	},
          ];
          
          let copiedUsers = users.slice();
          
          console.log(users === copiedUsers); // false, 다른 주소
          console.log(users[0] === copiedUsers[0]); // true, 같은 주소
      • 깊은 복사 : 참조 자료형 내부에 중첩되어 있는 모든 참조 자료형을 복사
        • JavaScript 내부적으로는 깊은 복사를 수행할 수 있는 방법이 없음
        • JavaScript의 다른 문법을 응용하면 깊은 복사와 같은 결과물을 만들어 낼 수 있음
          • JSON.stringify()JSON.parse()
            • 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
            • lodash를 활용한 예시
              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
반응형

댓글