[javascript] Object.assign() & Object.create()

chaeyeon·2023년 1월 18일
0
post-thumbnail
post-custom-banner
메서드 이름 설명
Object.assign() 하나 이상의 객체를 결합하여 지정한 객체에 복사한다.
Object.create() 지정한 속성을 갖는 새로운 객체를 생성한다.

1. assign()

Object.assign(target, sources, ...)

- target: 대상객체  - sources: 복사할 원본
sources...로 지정된 객체의 멤버를 target에 복사되어 결합 후의 객체를 반환된다. (target에도 영향을 미친다)
동일 명칭의 프로퍼티는 나중에 정의된 값으로 덮어 쓰여진다.

let pet1 = {
    type: 'cat',
    name: 'coco',
    description: {
        birth: '2020-08-17'
    }
};
let pet2 = {
    name: 'chuchu',
    color: 'black',
    description: {
        food: 'feed'
    }
};
let pet3 = {
    weight: 5,
    age: 2
};
Object.assign(pet1, pet2, pet3);
/* 
    pet1 = {
        age: 2,
        color: 'black',
        description: {  
            food: 'feed' 
        }
        name: 'chuchu',
        type: 'cat',
        weight: 5,
    }
*/

앞서 설명했듯이 target에 pet1이 지정되어 있기때문에 target객체인 pet1에 변화가 생겼다.
재귀적인 결합을 지원하지 않기때문에 description이 통째로 교체된다(birth → food)는 점에 주의한다.
만약, sources객체들에 영향을 끼치고 싶지 않다면, 다음과 같이 target에 {}를 지정해주면 빈 객체에 sources객체를 결합한 값들을 반환한다.

Object.assign({}, pet1, pet2, pet3);

2. create()

Object.create(proto[, props])
- proto: 생성할 객체의 원본 객체  - props: 프로퍼티 정보 (ex - {프로퍼티명 : { 속성명: 값, ... }, ... })

객체를 생성하는 수단에는 여러가지 방법이 있다.
// 1 - 객체 리터럴
const obj = { a: 1, b: 2, b: 3};

// 2 - new 연산자 이용
const obj2 = new Object();

// 3 - Object.create()이용

1, 2의 방법으로 생성된 객체는 Object의 인스턴스로써 Object의 기본 메서드를 계승하고 있다. (toString, valueOf등) Object.create메서드의 proto 인수에 null을 전달하면 Object의 프로토타입을 계승하지 않는 완전한 빈 객체를 만들 수 있다. (null이 전달되어 만들어진 객체는 toString, valueOf등의 메서드를 사용할 수 없다.)

// Object 프로토타입이 계승되지 않은 완전히 빈 객체 생성
Object.create(null)

Object.create로 빈 객체를 만들 수도 있지만 다양한 속성을 이용하여 커스텀도 가능하다. Object.create의 props에는 다음과 같은 프로퍼티 속성을 가질 수 있다.


프로퍼티 속성 개요 기본값
configurable 프로퍼티를 변경할 수 있는지 정하는 속성 false
enumerable 프로퍼티가 열거 가능한지 정하는 속성 false
value 프로퍼티의 값 저장 -
writable 프로퍼티에 값을 저장할 수 있는지 정하는 속성 false
get -
set -

// Object.create를 이용하여 Object 프로토타입을 계승한 새로운 객체 생성
let coffee = Object.create(Object.prototype, {
    name: { 
        value: 'Americano',
        writable: true,
        configurable: true,
        enumerable: true,
    },
    price: { 
        value: 4100,
        writable: true,
        configurable: true,
        enumerable: true,
    },
    get: {
        value: function() {
            return this.name;
        }
    },
    set: {
        value: function(name) {
            this.name = name
        }
    }
})
console.log(coffee.name)  // 'Americano'
console.log(coffee.price)  // 4100
console.log(coffee.get())  // 'Americano'
coffee.set('cafe latte')  
console.log(coffee.get())  // 'cafe latte'

위의 예제에서 configurable의 속성값을 true로 설정하였기 때문에 coffee.set()으로 name의 value값을 변경할 수 있었다. 위의 속성을 적절하게 사용하면 Object.create로 생성된 객체를 수정/복사 하여 활용할 수 있을 것이다.

3. Object.create() vs new Constructor()

Object.create를 다루는 자료들을 찾아보면 new Constructor()와 비교하는 글이 꽤 많았다. Object.create를 이용하는 것과 new키워드를 이용해 객체를 생성하는 것과의 공통점과 차이점은 뭘까?

function Coffee() {
  this.name = 'Americano';
}
Coffee.prototype.price = 4100;
let drink1 = new Coffee();  // 생성자를 이용한 객체 생성
let drink2 = Object.create(Coffee.prototype);  

console.log(drink1.name); // 'Americano'
console.log(drink1.price); // 4100
console.log(drink2.name); // undefined
console.log(drink2.price); // 4100

위의 예제를 보면 drink1.price와 drink2.price가 정상적으로 출력되었으며 price 프로토타입이 정상적으로 계승되었다는 것은 확인할 수 있다. 문제는 Coffee함수 내부에 선언된 name프로퍼티에 접근할 때 발생하였다.
생성자를 이용하여 선언한 drink1는 문제없이 name프로퍼티에 접근이 가능했지만 Object.create로 선언한 drink2변수는 name프로퍼티에 접근 시 undefined를 출력하였다. 즉 Object.create는 Constructor의 this.name에 접근할 수 없다.

- 왜 접근할 수 없는데?

Coffee함수의 프로토타입을 상속받는 생성자 객체 drink1를 만들면, Coffee는 drink1 객체의 this를 해당 객체에 바인딩 시킨다. Object.create로 만든 drink2는 단순히 Coffee함수의 프로토타입을 상속받아 객체를 생성했을 뿐이다. 따라서 프로토타입을 사용할 순 있지만, 생성자 함수의 내부 프로퍼티에 접근 할 수 없다.

공통점

  • 객체리터럴을 이용하기 때문에 새로운 객체를 만든다.
  • Constructor (위에서는 Coffee함수)의 프토로타입을 상속받는다.

차이점

  • new 키워드로 생성한 객체(위에서는 drink1)는 Constructor 함수를 실행한다.
  • Object.create()로 생성한 객체(위에서는 drink2)는 Constructor 함수를 실행하지 않는다.


참고 : 모던 자바스크립트 입문(이소 히로시), MDN

profile
4년차 퍼블리셔에서 프론트엔드 개발자로 이직 성공한 신입 개발자 입니다-*
post-custom-banner

0개의 댓글