본문 바로가기

JavaScript

중첩객체/불변객체/얕은복사/깊은복사

중첩객체
객체 안에 또다른 객체가 들어가는것을 중첩객체라 한다.

 

예시

let obj = { //객체
    name:"어쩌구",
    age:20,
    add{   //안에 중첩된 객체
     city:"seoul",
     gu:"giheung-gu"
     }

 

접근방법

  • ex : obj 의 city 값에 접근하고 싶은 경우
obj.add.city

 

 


불변객체
한 번 생성된 후 변경할 수 없는 객체를 말한다. 즉, 객체의 속성 값을 수정하거나 새로운 속성을 추가할 수 없다.
JS에서는 const 와 Object.freeze()메서드 를 사용하여 만들수 있다.

 


얕은복사
객체나 배열의 바로 아래단계의 속성만을 복사하는 방식이다. 즉, 원본 객체의 참조를 그대로 복사하기 때문에, 복사된 객체의 속성이 객체나 배열일 경우 이 속성들은 원본 객체와 동일한 참조를 가리킨다.

 

예시

 

  • 객체의 프로퍼티(속성) 에 접근해서 이름을 변경함 > 가변
// 객체 생성
let person = {
    name:"hong",
    gender:"male",
    }
    
    //이름을 변경하는 함수 정의
    //입력값 : function(변경대상:person객체, 변경하고자하는 이름)
    //출력값 : 새로운 person 객체 
   
    let nameChange = function(person(변경대상),newName(새로운이름){
    let newPerson = person //객체복사 ;
    newPerson.name = newName; //복사한 객체의 이름 = 새로운이름
    return newPerson //복사한 객체의 이름을 변경한값을 반환함
    }
    
    let person2 = nameChange(person,'cheong') //변경한 person 의 정보를 user2 변수에 할당함
    // 가변 이기 때문에 person 도 영향을 받게 된다.
    
    //결과적으로 person의 name도 cheong 으로 바뀜
    
    person.name === person2.name //true
  •  객체의 프로퍼티에 접근하는 것이 아니라 , 아예 새로운 객체를 반환 > 불변
//객체 생성
let person = {
    name:"hong",
    gender:"male",
    }
    
//이름을 변경하는 함수 정의
let nameChange = function(person,newName){
   return{ //아예 새로운 객체를 반환함 person과 아예 다른객체를 생성
   name:newName,
   gender:person.gender,
   } 
}

//변경한 person 정보를 person2에 변수에 할당
let person2 = nameChange(person,"cheong")

//결과

person === person2 // 유저 이름이 다르므로 false

//문제점 : 이 방식은 객체안에 값이 많아질수록 하드코딩을 해야하기때문에
//코드가 무거워질 수 있음 

//예시
let person = {
    name:"hong",
    gender1:"male",
    gender2:"male",
    gender3:"male",
    gender4:"male",
    gender5:"male",
    gender6:"male",
    gender7:"male",
    gender8:"male",
    gender9:"male",
    gender10:"male",
    gender11:"male",
    gender12:"male",
    
    }
  • for...in 구문을 이용하기
//객체를 복사하는 함수를 정의

let copyObject = function (target(객체)) {
  let res = {};
  for (let prop in target) {
    res[prop] = target[prop]; //객체의 프로퍼티에 하나하나 접근하여 복사함
  }
  return res; //복사된 객체를 반환함
};

//////////////////////////////////////////

//기본 객체
let person = { 
    name:"hong",
    gender:"male",
}

//객체 복사
let person2 = copyObject(person(복사할 객체))
person2.name = "cheong" //변경할 이름 


//결과
person2.name !== person.name // 두 결과가 다르므로 true

//문제점 : 얕은복사 이기 때문에 중첩된 객체에 대해서는 완벽하게 복사할 수 없다.
//얕은복사 : 바로 아래 단계의 값만 복사할 수 있다.
//중첩된 객체의 경우 참조형 데이터가 저장된 프로퍼티를 복사할 때 , 주소값만 복사함

/////////////////////////////////////////////////////////////////////////////

//중첩객체의 경우
//객체를 반복하여 복사
let copyObject = function (target) {
  let res = {};
  for (let prop in target) {
    res[prop] = target[prop];
  }
  return res;
};

//중첩된 객체

let person = {
  name: "dlfma",
  info: {
    //중첩된 객체
    por: "어쩌구",
    blog: "저쩌구",
  },
};
//여기까진 복사 가능 이름은 1뎁스 바로아래뎁스 이기 때문에 복사가 가능하다
let person2 = copyObject(person); //person : target

person2.name = "새 이름";

// 바로 아래 단계에 대해서는 불변성을 유지하기때문에 값이 달라진다.
console.log(person.name === person2.name); // false

//하지만 더 깊은 단계에 대해서는 불변성을 유지하지 못하기 때문에 값이 같아짐
//urls의 blog 를 변경하려할 경우
user2.urls.blog = "변경할 값";
//위 처럼 작성할 경우
//user 의 blog와 user2의 blog의 값이 같아짐
console.log(user.urls.blog === user2.urls.blog); //true

깊은복사
내부의 모든 값 들을 하나하나 다 찾아서 모두 복사하는 방법이다.
원본 객체의 중첩된 객체나 배열까지 모두 새롭게 복사되기 때문에, 복사된 객체는 원본 객체와 완전히 독립적으로 동작한다.

깊은복사를 하기위해서는 재귀적 수행방법을 사용해야한다.
재귀적 수행방법 (re+cursive): 함수나 알고리즘이 자기 자신을 호출하여 반복적으로 실행되는 것을 말한다.

 

  • 재귀적 수행방법을  이용하기
let copyDeepObj = function (target) {
  let res = {};
  if (typeof target === "object" && target !== null) { //타겟이 객체이거나 빈값이 아닐때 실행
    for (let prop in target) {
      res[prop] = copyDeepObj(target[prop]);
    }
  } else {
    res = target;
  }
  return res;
};

//결과

let person = {
  name: "hong",
  job: {
    jobName: "백수",
    money: 10,
  },
};
//객체에 값을 하나하나 변경함
let person2 = copyDeepObj(person);
person2.job.money = 300;
person2.job.jobName = "개발자";
person2.name = "cheong";

 

 

  • JSON 이용하기

JSON 을 이용한 방법
완벽한 방법은아님
장점
1,JSON.stringify() 함수를 사용하여 객체를 문자열로 변환한 후 , 다시 JSON.parse()함수를 사용하여새로운 객체를 생성하기 때문에 원복 객체와 복사본 객체가 서로 독립적으로 존재한다.따라서 복사본 객체를 수정하더라도 원본 객체의 영향을 미치지 않는다.
2,JSON을 이용한 깊은 복사는 다른 깊은 복사 방법에 비해 코드가 간결하고 쉽게 이해됨

단점
1,JSON을 기용한 깊은 복사는 원복 객체가 가지고 있는 모든 정보를 복사하지 않는다.
예를 들어 함수나 undefined같은 속성값은 복사되지 않는다.
2, JSON.stringify() 함수는 순환 참조(Recursive Reference)를 지원하지 않는다. 따라서 객체안에 객체가 중첩되어 있는경우이 방법으로는 복사할 수 없다.결론JSON을 이용한 깊은 복사는 객체의 구조가 간단하고 함수나 undefined 와 같은 속성 값이 없는 경우에 적합한 방법이다.만약 객체의 구조가 복잡하거나 순환 참조가 있는 경우에는 다른 깊은 복사 방법을 고려해야 한다.