[Javascript] 객체를 복사하는 create()와 assign() 메서드의 차이

create()와 assigne() 메서드는 기존 객체를 복사해서 새 객체를 생성하는 Object 객체의 메서드입니다.

두 메서드는 객체의 복사본을 생성하는 점은 같지만, 중요한 차이점이 있습니다.

차이점을 알고 사용해야 복사한 객체의 용도에 따라 적절한 사용이 가능합니다.

다음 클래스를 객체로 생성해서 create()와 assign() 메서드로 객체 복사를 해보겠습니다.

각각의 메서드로 복사한 필드 값을 콘솔에 표시하면 같은 필드 값이 표시됩니다.

class User {
    name = '라이언'
    constructor(){
 	    this.vip = true;
    }
}
    
const user = new User();

const assigned = Object.assign({}, user)
const created = Object.create(user);

console.log(assigned.vip, assigned.name) // true '라이언'
console.log(created.vip, created.name) // true '라이언'

동일하게 복사된 것 같지만 최초 생성한 user 객체의 name 필드 값을 변경한 후 다시 복사한 객체들의 값을 확인하면 다음과 같이 달라집니다.

assign() 메서드로 복사한 객체는 복사된 필드 값이 그대로 유지되지만, created() 메서드로 복사한 객체는 원본 객체의 필드 값을 표시합니다.

user.name = '어피치'

console.log(assigned.vip, assigned.name) // true '라이언'
console.log(created.vip, created.name) // true '어피치'

create() 메서드로 복사한 created 객체가 원본 객체의 필드 값을 참조하는 것인지 확인하려면 다음처럼 두 객체의 필드 값을 순차적으로 변경해 보면서 값을 표시해 보면 됩니다. create() 메서드로 복사한 created 객체의 name 필드를 "프로도"로 변경하면 변경 값이 복사 객체인 created 객체의 name 필드에 적용됩니다.

그리고 원본 객체인 user 객체의 name 필드 값을 "단무지"로 변경하면 앞서와 달리 created 객체의 name 필드 값이 "프로도" 그대로 유지가 됩니다.

create() 메서드로 복사한 created 객체의 필드 값은 원본 객체인 user 객체의 필드 값을 참조합니다.

복사한 created 객체의 필드에 새로운 값을 적용하면 비로소 created 객체의 필드는 고유의 필드 값을 가지게 됩니다.

created.name = '프로도'
user.name = '단무지'
 
console.log(assigned.vip, assigned.name) // true, '라이언'
console.log(created.vip, created.name) // true, '프로도'
console.log(user.vip, user.name) // true, '단무지'

이와 달리 assign() 메서드로 복사한 assigned 객체는 원본 객체인 user 객체의 필드 값 변화와 무관하게 고유의 필드 값을 계속 유지하고 있습니다.

assign() 메서드는 원본 객체를 복사하는 시점에 필드 값까지 모두 복사해서 원본 객체와는 분리된 완전히 새로운 객체를 생성합니다.

이렇게 필드 값까지 모두 복사를 하는 방식을 딥 카피(Deep Copy)라고 하고, 복사를 하는 시점에는 필드의 참조를 통해 원본 객체의 값을 참조하도록 하는 방식을 셸로우 카피(Shallow Copy)라고 합니다.

셸로우 카피를 하면 복사된 객체의 필드가 원본 필드의 값 대신 원본 객체 필드를 참조하 주소만 담고 있기 때문에 데이터 공간을 차지하지 않는 장점이 있습니다.

그리고, 복사한 여러 객체에서 같은 값을 유지하는 필드의 값은 원본 객체의 필드 값만 변경을 하면 모든 객체의 필드가 같은 값을 표시하게 되기 때문에 객체의 관리 측면에서 유지가 편리한 장점이 있습니다.

let user1 = new User();
let user2 = Object.create(user1);
let user3 = Object.create(user1);
user2.name = '어피치'
user3.name = '프로도'
user1.vip = false

console.log(user1.name, user2.name, user3.name); // 라이언, 어피치, 프로도
console.log(user1.vip, user2.vip, user3.vip); // false, false, false

원본 객체인 user1 객체의 vip 속성을 false로 변경하면, 복사해서 생성한 나머지 두 객체의 vip 필드 속성도 모두 false로 표시됩니다.