(39) JavaScript - 자료형(심화) / 참조형 copy하기

반응형

참조형 값은 변수에 할당될 때 값 자체가 아닌 주소값이 할당된다고 했을 때,

    let number1 = [1, 2, 3]
    let number2 = number1
    
    number2.push(4)

    console.log(number1);
    console.log(number2);

▲ 코드를 보면 배열도 참조형이기 때문에 number1에 배열[1,2,3]의 주소값이 할당되고

number1이 가지고 있는 배열의 주소값이 복사가 돼서 number2만 변경했지만 

코드를 실행하면 number1도 변경된 모습을 확인 할 수 있다.

 

그런데 상황에 따라서는 이 참조형 값을 그대로 복사해야 할 경우가 있다.

말 그대로 number2만 변경할 때의 경우인데,

이럴 때 배열의 경우에는 'slice' 메소드를 활용하면 해결할 수 있다.

    let number1 = [1, 2, 3]
    let number2 = number1.slice() //slice 추가
    
    number2.push(4)

    console.log(number1);
    console.log(number2);

▲ slice 메소드를 호출할 때 파라미터 값을 전달하지 않으면

원래 값이 그대로 리턴되는 특성을 활용해서 

마치 배열을 복사하는 것과 같은 효과를 얻을 수 있다.

실행해보면 number2만 변경된 것을 확인할 수 있다.

 

이번에는 객체로 살펴보자면..


    let course1 = {
        title: '파이썬',
        language:'Python'
    }

    let course2 = course1

    course2.title = '알고리즘'

    console.log(course1);
    console.log(course2);

▲첫 번째 course 데이터를 담은 객체를 복사해서 title만 바꿔줬지만 

course1도 title이 변경된 것을 확인할 수 있는데,

 

객체에는 배열 처럼 slice를 사용할수 없지만

자바스크립트에서 Object라는 객체의 assign 메소드를 활용해서 복사를 할 수 있다.

 

assign 메소드

    let course1 = {
        title: '파이썬',
        language:'Python'
    }

    let course2 = Object.assign({}, course1) // 추가

    course2.title = '알고리즘'

    console.log(course1);
    console.log(course2);

이렇게 course2만 title이 변경된 것을 확인할 수 있다.

 

그런데 좀 더 직관적으로 이해하기 위해서

메소드를 활용하지 말고 for...in문으로 객체를 복사해보자면..

 

for...in문으로 객체 복사

 

    let course3 = {
        title: '파이썬',
        language:'Python'
    }

    // let course2 = course1
    //let course2 = Object.assign({}, course1)
    
    let course4 = {} //빈 객체 생성
    for(let key in course3){ //for...in문 생성
        course4[key] = course3[key]
    }
    

    course4.title = '자료구조'

    console.log(course3);
    console.log(course4);

▲ 그냥 빈 객체를 만든 다음에 course1(course3)으로 for...in문을 작성해서 각 프로퍼티들을 넣어주면

똑같은 프로퍼티를 가지고 있지만 서로 독립적은 객체로 복사를 할 수 있다.

실행해보면 이번에도 title만 바뀐 것을 확인할 수 있다.

 

그런데 for문은 변수들(course)에만 한정적인 것 같아보인다.

변수가 점점 늘어나면 또 for문을 작성해야한다.

for문은 사용하되 함수로 만들어주게 바꿔보자면.. (함수 사용은 맨위로 올림) 

 

function을 활용한 객체 복사

    function cloneObject(object){ //파라미터로 복사할 객체를 전달  
        let temp = {} //빈 객체

        for (let key in object){
            temp[key] = object[key]
        }
        return temp
    }

    let course5 = {
        title: '파이썬',
        language:'Python'
    }

    // let course2 = course1
    // let course2 = Object.assign({}, course1)
    let course6 = {} //함수 호출
    
    course4.title = '자료구조'

    console.log(course5);
    console.log(course6);

▲ 파라미터로 복사할 객체를 전달 받고 

임시로 빈 객체를 만든 다음에 for...in문을 통해 객체를 복사하고 임시 객체를 리턴해 주고있다.

    let course6 = cloneObject(course5) //함수 호출

▲ 그래서 course6(기존course2)에 함수를 호출하는 값을 변수에 할당해 주게 되면

복사된 객체가 변수에 담기게 된다.

 

함수를 생성하여 그 내부에 for...in문을 활용해,

이제는 course가 늘어나도 함수를 활용할 수 있게된다. 한번 자바스크립트를 복사해보자면..▼

    function cloneObject(object){
        let temp = {}

        for (let key in object){
            temp[key] = object[key]
        }
        return temp
    }

    let course5 = {
        title: '파이썬',
        language:'Python'
    }

    // let course2 = course1
    // let course2 = Object.assign({}, course1)
    let course6 = cloneObject(course5) //함수 호출
    let course7 = cloneObject(course5) //함수 호출2

    course6.title = '자료구조'
    course7.title = '자바스크립트'

    console.log(course5);
    console.log(course6);
    console.log(course7);

 

어떤 상황이던 간에 파라미터만 변경해주면 되니깐 훨씬 더 효율적으로 활용할 수 있다.

 


▼ 주의할점(배열 프로퍼티 추가 관련)

더보기
    function cloneObject(object){
        let temp = {}

        for (let key in object){
            temp[key] = object[key]
        }
        return temp
    }

    let course8 = {
        title: '파이썬',
        language:'Python',
        test : [] // 배열 추가
    }

    // let course2 = course1
    // let course2 = Object.assign({}, course1)
    let course9 = cloneObject(course8) 
     
    course9.title = '자료구조'
    course9.test.push('배열추가test') //객체복사

    console.log(course8);
    console.log(course9);

 

▲ test 프로퍼티에 배열을 추가해서 객체를 복사하려고 했는데

'배열추가test'가 추가된 것을 확인할 수 있다.

 

왜냐하면 test 프로퍼티가 배열이기 때문에 또 주소값이 복사돼 버린 것이다.

이러한 문제는 앞서 살펴봤던 배열의 slice 메소드나 object 객체의 assign 메소드나

모두 동일하게 발생하는 문제이며

객체나 배열 안에 중첩해서 객체나 배열이 있는 경우에는 복사할 때

또 주소값이 복사되기 때문에 예상치 못한 결과를 얻을 수 있어서

그러므로.. 일단은 이러한 문제가 있다는 것만 인지하자.

★GitHub 주소 (참조형 copy)

https://github.com/SeopE9611/JavaScript_soloPlay/blob/main/Basic/10-%EC%9E%90%EB%A3%8C%ED%98%95(%EC%8B%AC%ED%99%94)/7.%EC%B0%B8%EC%A1%B0%ED%98%95%EB%B3%B5%EC%82%AC.html

 

JavaScript_soloPlay/Basic/10-자료형(심화)/7.참조형복사.html at main · SeopE9611/JavaScript_soloPlay

Contribute to SeopE9611/JavaScript_soloPlay development by creating an account on GitHub.

github.com

 

★Notion 주소 (배열 추가 및 수정하기)

https://purrfect-gargoyle-935.notion.site/115e9530b3e180eb861fefd32891f7ec?pvs=4

 

배열 정리 | Notion

커피 메뉴 레시피를 만들기 ▼

purrfect-gargoyle-935.notion.site

반응형