코딩.zip

[객체&배열] 딱복? 물복?의 시대는 갔다 얕복 vs 깊복의 차이를 알아보자 (얕은 복사, 깊은 복사) 본문

프로그래밍/JavaScript

[객체&배열] 딱복? 물복?의 시대는 갔다 얕복 vs 깊복의 차이를 알아보자 (얕은 복사, 깊은 복사)

김주짱 2024. 3. 7. 17:42

▶ 얕은 복사(shallow Copy)

주소값(참조값)을 복사해서 복사본과 원본 모두 영향을 미침
    <script>
        const object_202403 = ['우유', '식빵']
        
        // 얕은 복사 : 객체의 주소값을 복사
        const object_202404 = object_202403

        object_202404.push('딸기잼')
        object_202404.push('커피')

        console.log(object_202403)
        console.log(object_202404)
    </script>
    
    <!-- 실행 결과 
    (4) ['우유', '식빵', '딸기잼', '커피']
    (4) ['우유', '식빵', '딸기잼', '커피']
    -->

 

🚨 잠깐, const로 선언된 변수는 상수값을 가지는데 어떻게 요소를 추가 했을 때 Error가 뜨지 않았을까?

const로 선언된 변수는 재할당이 불가능한 상수이다. 그러나 const로 선언된 객체(배열 포함)는 객체의 내부 요소가 변경될 수 있다.

얕은 복사(shallow copy)는 객체의 주소값을 복사해서 새로운 변수에 할당하기 때문에 object_202404object_202403같은 객체를 참조하고 있다.


 깊은 복사(deep Copy)

실제값을 새로운 메모리에 복사해서 완전히 새로운 객체 생성
    <script>
        const object_202403 = ['우유', '식빵']
        
        // 깊은 복사 : 객체의 실제 값을 복사
        const object_202404 = [...object_202403]

        object_202404.push('딸기잼')
        object_202404.push('커피')

        console.log(object_202403)
        console.log(object_202404)
    </script>
    
    <!-- 실행 결과 
    (2) ['우유', '식빵']
    (4) ['우유', '식빵', '딸기잼', '커피']
    -->

 

깊은 복사(deep copy)를 사용하면 주소값이 아닌 객체의 실제 내용을 복사하게 되고, 이 경우 두 변수는 서로 독립적으로 처리되어 새로운 요소 추가 시 원본값은 변하지 않는다.

 


✅  전개 연산자(spread Operator)

배열이나 객체의 요소를 펼쳐서 새로운 배열이나 객체를 생성할 때 사용

 

표현 방법 : '...객체명'

- 배열(array)의 전개 연산자

    <script>
    const object_202403 = ['우유', '식빵']
    
    // 고구마가 인덱스[0]이 되고 토마토가 인덱스[4]가 된다.
    const object_202404 = ['고구마', ...object_202403, '토마토']

    console.log(object_202403)
    console.log(object_202404)
    </script>
    
        <!-- 실행 결과 
    (2) ['우유', '식빵']
    (4) ['고구마', '우유', '식빵', '토마토']
    -->

 

'...object_202403' : object_202403 배열의 모든 요소를 펼쳐서 새로운 배열 object_202404 를 만든다는 뜻

 

- 전개 연산자 위치에 따라 인덱스 결과가 달라지는 것을 기억해야 한다. 만약 [...object_202403, '고구마', '토마토'] 순서였다면 실행 결과값이 ['우유', '식빵', '고구마', '토마토']로 달라졌을 것이다.

 

- 객체(object)의 전개 연산자

    <script>
        const 송이 = {
            이름 : '송이',
            나이 : 12,
            종류 : '강아지' 
        }

        const 코코 = {
            ...송이,
            이름 : '코코',
            나이 : 5,
            예방접종:true
        }

        console.log(JSON.stringify(송이))
        console.log(JSON.stringify(코코))
    </script>
    
    <!-- 실행 결과 
    {"이름":"송이","나이":12,"종류":"강아지"}
    {"이름":"코코","나이":5,"종류":"강아지","예방접종":true}
    -->

 

'...object_202403' : object_202403 객체의 모든 속성을 펼쳐서 새로운 객체 object_202404 를 만든다는 뜻

 

 → 객체에서의 전개 연산자도 어디에 위치 시키느냐에 따라 결과값이 아예 달라질 수 있다.

    <script>
        const 송이 = {
            이름 : '송이',
            나이 : 12,
            종류 : '강아지' 
        }

        // 전개 부분을 마지막에 작성
        const 코코 = {
            이름 : '코코',
            나이 : 5,
            예방접종:true,
            ...송이
        }

        console.log(JSON.stringify(송이))
        console.log(JSON.stringify(코코))
    </script>
    
    <!-- 실행 결과
    {"이름":"송이","나이":12,"종류":"강아지"}
    {"이름":"송이","나이":12,"예방접종":true,"종류":"강아지"}
    -->

 

- 코코 객체를 생성 후 '...송이'  객체를 마지막에 전개 했을 때, 코코 객체가 송이 객체 속성들을 덮어쓰게 된다.

- 또한 송이 객체에 없는 '예방접종:true' 속성을 새로 생성하였기 때문에 결과값에 추가되며

- 송이 객체에서 가져온 '종류:강아지'는 전개 연산자 위치에 의해 맨 마지막에 추가되어 결과값에 나타난다.

 


 

처음에 '...'만 보고 나머지 매개변수인줄 알았다.. 그래서 혹시나 나 같은 사람이 있을까봐^^ 두 개 구분하는 방법을 찾아보았다.

함수 호출 시 사용 → 배열을 목록으로 확장해주는 전개 연산자
함수 매개변수의 끝에 위치 → 인수 목록의 나머지를 배열로 모아주는 나머지 매개변수

출처: https://inpa.tistory.com/entry/JS-📚-전개-연산자Spread-문법 [Inpa Dev 👨‍💻:티스토리]

 

나 구분 할 수 있겠지..(응 해야지.