2024/03/29 참조에 의한 객체 복사

YIS·2024년 3월 29일
post-thumbnail

참조에 의한 객체 복사

원시값(문자열, 숫자, 불린 값 등)은 값 자체가 변수에 저장되는 반면,
객채는 메모리에 저장된 후 변수에서 그 메모리 주소를 참조하는 참조 값이 저장됨.
객채를 또 다른변수에 할당하면, 두 변수는 같은 객체를 가리키게됨.

let user = { name: "John" };
let admin = user; // 'user'의 참조 값을 'admin'에 복사
admin.name = 'Pete'; // 'admin'을 통해 객체의 'name' 속성을 변경
alert(user.name); // 'Pete'가 출력됨. 'user'도 동일한 객체를 참조하기 때문.

참조에 의한 비교

let a = {};
let b = a; // a의 참조값을 b에 할당
alert(a == b); // true, 
alert(a === b); // true // a와 b는 같은 객체를 참조함.

객체는 메모리에 저장되고, 변수는 그 메모리 주소를 참조함.
따라서, 두 변수가 같은 객체를 참조하면, 그 두 변수는 사실상 같은 객체를 가리키고 있는 것.

독립된 객체의 비교

let a = {};
let b = {}; // 독립된 객체 생성
alert(a == b); // false, 
alert(a === b); // false // a와 b는 서로 다른 객체.

각각 독립적으로 생성된 두 객체는 서로 다른 메모리 주소를 가지고 있음.
따라서, 비록 내용이 같아 보일지라도, 두 객체는 서로 다른 것으로 간주됨

객체와 원시값의 비교

객체를 원시값과 비교할 때, 객체는 원시형으로 변환됨.
이 과정은 자바스크립트 내부에서 자동으로 이루어지며,
대부분의 경우 이러한 비교는 의도하지 않은 결과를 초래할 수 있음.
따라서 객채끼리의 대소 비교나, 원시값과 객체를 비교하는 것은 일반적인 상황에서는 바람직하지않음.




객체 복사, 병합과 Object.assign

기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶은 경우,
자바스크립트는 현재 객체 복제 내장 메서드를 지원하지 않음. 그래서
새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해
원시 수준까지 프로퍼티를 복사하는방법이나,
Object.assign를 사용하는 방법이 있음

객체복사

let user = {
  name: "John",
  age: 30
};
let clone = {}; // 새로운 빈 객체

for (let key in user) {
  clone[key] = user[key];
}// 빈 객체에 user 프로퍼티 전부를 복사해 넣음.
// 이제 clone은 완전히 독립적인 복제본이 됨.
clone.name = "Pete"; // clone의 데이터를 변경.
console.log(clone.name); //pete
console.log(user.name); // 기존 객체는 여전히 John.

복습겸 for..in문 풀어서설명하면
key라는 매개변수를 만들고 전역변수 user안 객채의 모든 프로퍼티를 순회함.
반복할 때 마다 key에 프로퍼티값을 넣음.
첫번째반복에서 key는 name. 따라서 clone[key(name)] = user[key(name)]가 되고
클론객채에 name라는 프로퍼티가 추가가 되고 그값으로 user의 name값인 "John"이 할당됨.
두번째 반복도 똑같음 age가 클론객채에 추가되고 그값으로 유저안의 age의값 30이 할당.

Object.assign

기본문법
Object.assign(dest, [src1, src2, src3...])

  • dest : 복사된 속성이 병합될 대상 객체. 이 객체가 변경되어 반환됨.
  • src1,src2... : 복사할 속성을 포함하는 하나 이상의 소스 객체. 여러 개의 전달 가능.
  • 객채 복사
let user = {
  name: "John",
  age: 30
};
let clone = Object.assign({}, user);
//let clone = {};  
//Object.assign(clone, user);
console.log(user); //{name: 'John', age: 30}
console.log(clone); //{name: 'John', age: 30}
console.log(user == clone); //false

user에 있는 모든 프로퍼티가 빈 배열에 복사되고 변수에 할당됨.

  • 객채 병합하기
let user = { name: "John" };
let permissions1 = { canView: true , canEdit: false};
let permissions2 = { canEdit: true };

Object.assign(user, permissions1, permissions2);
// permissions1과 permissions2의 프로퍼티를 user로 복사.
//동일한 이름을 가진 프로퍼티가 있는 경우엔 (ex : canEdit)
//기존 값이 덮어씌워 짐.
console.log(user) // { name: "John", canView: true, canEdit: true } canEdit 덮어 씌워짐.



중첩 객체 복사

객체의 프로퍼티값이 원시값인 경우는 위에 예시로 가능함.
하지만 객체안의 프로퍼티값이 또다른 객체일 경우는 위의 방법으로는 복사 할 수 없음.

let user = {
  name: "John",
  size: {width : 70 ,heigth : 180}
};
let clone = {}; // 새로운 빈 객체

for (let key in user) {
  clone[key] = user[key];
}// 빈 객체에 user 프로퍼티 전부를 복사해 넣음.

clone.name = "Pete"; // clone의 데이터를 변경.
console.log(clone.size); //{width: 70, heigth: 180}
console.log(user.size); // {width: 70, heigth: 180}
console.log(clone === user); // false 
console.log(clone.size === user.size); //true
//user 과 clone는 다른 객채지만 
//그 안의 size라는 객채는 복사해서다른 값이 아닌 서로 같은 값을 참조한 결과물을 출력함

수동복사경우

let user = {
  name: "John",
  sizes: {
    height: 182,
    width: 50
  }
};
let clone = Object.assign({}, user);
console.log( user.sizes === clone.sizes ); // true, 같은 객체.
// user와 clone는 sizes를 공유함.
user.sizes.width++;       //  user객체에서 프로퍼티sizes안 width를 변경.
console.log(clone.sizes.width); // 51, clone 객체에서 변경 사항을 확인할 수 있음.

Object.assign경우

위 두 경우는 얇은 복사(실제로는 내부의 중첩된 객체는 동일한 참조를 가지는 경우)임.
그래서 user[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 함(이런 방식을 '깊은 복사(deep cloning)라고함.)
자바스크립트 라이브러리 lodash의 메서드인 _.cloneDeep(obj)을 사용하면 이 알고리즘을 직접 구현하지 않고도 깊은 복사를 처리할 수도 있음.

profile
엉덩이가 무거운 사람

0개의 댓글