Programing/Design Patterns

Javascript 프로퍼티 복사를 통한 상속 패턴 깊은복사 얕은복사 배열 객체 구분

리커니 2022. 3. 11. 17:47
반응형

Javascript 프로퍼티 복사를 통한 상속 패턴 깊은복사 얕은복사 배열 객체 구분

 

부모 객체의 프로퍼티를 자식의 프로퍼티에 추가하는 방법입니다.

예시 코드를 보시죠.

 

const parent = {name: "알짜배기 프로그래머"};
let child = {};

const extend = function(parent, child){
    child = child || {};
    for(let prop in parent){
    	child[prop] = parent[prop];
    }
    return child;
}

child = extend(parent, child);

console.log(parent, child)

 

console 창의 결과는 아래와 같습니다.

 

 

단순히 반복문을 돌면서 property 값을 추가하기 때문에 같은 구조를 갖게 됩니다.

 

그럼 child의 name property 값을 변경하면 어떻게 될까요? 아래의 코드를 추가해봅시다.

 

child.name = "웹 개발자";
console.log(parent, child);

 

 

이렇게 기본형 property 값의 경우 상속을 받아도 자신의 값만 변경되게 됩니다.

그럼 참조형 변수의 경우에도 자식의 값만 변경이 될까요?

name property의 값을 Array로 변경해보겠습니다.

 

const parent = {name: ["알짜배기", "프로그래머"]};
let child = {};

const extend = function(parent, child){
    child = child || {};
    for(let prop in parent){
    	child[prop] = parent[prop];
    }
    return child;
}

child = extend(parent, child);
child.name[1] = "웹 개발자";
console.log(parent, child);

 

 

결과를 보면 parent와 child 두 객체의 name 값이 모두 변경된 것을 보실 수 있습니다.

Javascript 는 참조형의 경우 참조주소가 전달이 되기 때문에 값을 변경할 경우

모두 영향을 받는 것을 보실 수 있습니다.

 

위와 같이 참조형 주소값이 복사되어 서로 영향을 받는 것을 '얕은 복사(shallow copy)' 라고 합니다.

 

그럼 참조형이더라도 서로 영향을 받지 않고 복사하는 방법인 '깊은 복사(deep copy)' 에 대해 알아보겠습니다.

아래의 링크를 보시면 JSON을 활용해 간단히 깊은 복사를 하는 방법이 있습니다.

 

Link : https://aljjabaegi.tistory.com/527

 

Javascript Object Extend, merge, copy 객체 합치기, 병합하기 복사하기

Javascript Object Extend, merge, copy 객체 합치기, 병합하기 복사하기 이번 포스팅에서는 Javascript 에서 Object를 다루는 방법을 알아보겠습니다. Object 선언 //리터럴방식 var obj = {a:'a', b:'b'..

aljjabaegi.tistory.com

 

하지만 이 방법은 깊은 복사를 흉내 낸 것입니다.

JSON.stringify(); 메소드를 통해 객체를 String으로 변환하고, 다시 이 String을 JSON.parse();를 통해 객체화 한 것 입니다.

간단하게 활용할 순 있지만, 실제 깊은 복사 로직은 아니라는 것은 알고 있어야 합니다.

 

그럼 위의 extend 함수를 깊은 복사가 되도록 변경해보겠습니다.

 

const extend = function(parent, child){
    const getObjType = function(obj){
        return Object.prototype.toString.call(obj).slice(8, -1);
    }
    child = child || {};
    for(let prop in parent){
    	if(typeof parent[prop] === "object"){
            child[prop] = (getObjType(parent[prop]) === "Array") ? [] : {};
            extend(parent[prop], child[prop]);
    	}else{
            child[prop] = parent[prop];
    	}
    }
    return child;
}

 

Object 와 Array 의 typeof  결과가 모두 object 로 리턴되기 때문에 

내부 함수인 getObjType()를 통해 Object 인지 Array 인지를 구분합니다.

구분에 따라 초기화 하고 재귀호출을 하여 값을 복사를 하게 됩니다.

 

이제 parent에 Object를 하나 추가하고 값을 변경하여 실제로 영향을 안받는지 확인해보겠습니다.

 

const parent = {
	name: ["알짜배기", "프로그래머"],
	etc: {homepage: "aljjabaegi.tistory.com"}
};
let child = {};

child = extend(parent, child);
child.name[1] = "웹 개발자";
child.etc.homepage = "http://aljjabaegi.tistory.com";
console.log(parent, child);

 

 

console 결과를 보시면 chlid 객체의 값만 변경된 것을 확인하실 수 있습니다.

 

개발을 하다보면 얕은 복사를 해야될 경우도 있고 깊은 복사를 해야되는 경우도 있습니다.

두 가지의 차이를 알고 용도에 맞게 활용하도록 합시다!

 

참고 : Javascript Patterns 스토얀 스테파노프

반응형