Object.create()

후훗♫·2020년 1월 11일
9

2020년 1월, 바닐라코딩 7기 부트캠프를 다니고 있다.
앞으로 부트 캠프를 다니는 동안 배우는 것들을 조금씩, 그리고 꾸준히 끄적이려고 한다.

바닐라코딩 후기도 남겨야되는데.... 차근차근해야지 흐흐

Object.create()

Object.create(proto[, propertiesObject])

정의

지정된 프로토타입 객체 및 속성(property)을 갖는 새 객체를 만듭니다.

매개변수

  1. proto
    새로 만든 객체의 프로토타입이어야 할 객체.
  2. propertiesObject
    선택사항. 지정되고 undefined가 아니면,
    자신의 속성(즉, 자체에 정의되어 그 프로토타입 체인에서 열거가능하지 않은 속성)이
    열거 가능한 객체는 해당 속성명으로 새로 만든 객체에 추가될 속성 설명자(descriptor)를
    지정합니다.
    이러한 속성은Object.defineProperties()의 두 번째 인수에 해당합니다.

출처 MDN

Object.create()를 공부하면서 헷갈렸던 부분은 크게 2가지이다.

1. 새 객체를 만들어준다????

MDN 문서에 따르면 Object.create()는
프로토타입 객체 및 속성(optional) 을 갖는 새 객체 를 만들어준다고 정리되어있다...

처음 보면.... 무슨 말을 하고 있는건지... 울고싶었다ㅋㅋㅋ........

코드로 Object.create()를 이해해보자.
코드는 MDN에서 가져왔다.

// Shape - 상위클래스
function Shape() {
  this.x = 0;
  this.y = 0;
};

// 상위클래스 메서드
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved.');
};

// Rectangle - 하위클래스
function Rectangle() {
  Shape.call(this);
};

현재 상태에서 console.log를 확인해보자.

console.log(Rectangle.prototype);
// ▼ {constructor: ƒ}
//   ► constructor: ƒ Rectangle()   -> constructor 프로퍼티가 Rectangle 생성자함수를 가리키고 있다.
//   ► __proto__: Object   -> 프로토타입 체인으로 부모 객체와 연결된다.

console.log(Rectangle.prototype.__proto__);
// ▼ {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ …}
//   ► constructor: ƒ Object()
//   ► ....
  • Rectangle 프로토타입 객체 에는 constructor 프로퍼티 를 가지고 있고,
    그 프로퍼티는 자신을 생성한 생성자함수 Ractangle 를 가리키고 있다.
  • __ proto __ 를 확인하면,
    Rectangle의 프로토타입 객체의 부모 객체Object 프로토타입 객체 가 나온다.

여기서 잠시, proto 를 정리하고 가자.

([[prototype]]이 proto 와 같은거다!)

proto 혹은 [[prototype]]

  • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
  • 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype를 가리킨다.

출처 Poiemaweb

현재 단계에서 Object.create()함수를 사용하면, console.log 값은 어떻게 변할까?

Rectangle.prototype = Object.create(Shape.prototype);

console.log(Rectangle.prototype);
// ▼ Shape {}   -> 빈 객체!!!! 새 객체가 만들어졌다! 아까는 constructor 프로퍼티가 있는 객체였다.
//   ► __proto__: Object 

console.log(Rectangle.prototype.__proto__);
// ▼ {move: ƒ, constructor: ƒ}
//   ► move: ƒ (x, y)   -> Shape 프로토타입의 Move 메소드가 보인다!!
//   ► constructor: ƒ Shape()
//   ► __proto__: Object
  • Rectangle 프로토타입 객체 를 보면, {} 라고 빈 객체 가 생성되어있다.
    MDN이 말하던 "새 객체" 이다.
  • Object.create()함수인자 로 전달된 Shape 프로토타입 객체
    새로 만들어진 객체프로토타입 객체 로 할당한다.
    그래서 프로토타입 체인을 통해 Shape 프로토타입의 Move 메소드를 사용할 수 있다.

여기서 중요한 사실은!

Object.create()을 사용할 경우, 새로 만들어진 객체에는 constructor 프로퍼티가 없다!!
그래서 constructor 프로퍼티를 만들고, 그 프로퍼티가 자신을 생성한 함수를 가리키도록
재 할당 해줘야한다.

(나는 '새 객체'를 설명하기 위해 재 할당을 해주지 않은 상태로 설명했다.)
// Object.create()을 다시 사용하자. 
// 새로 만들어진 프로토타입 객체는 자기 자신을 생성한 함수를 가리키는 constructor 프로퍼티가 없다.
// 따라서 다시 만들어 줘야한다.
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

console.log(Rectangle.prototype);
// ▼ Shape {constructor: ƒ}   -> 아까와 달리 빈객체가 아니다!
//   ► constructor: ƒ Rectangle()   -> 새로 만들어준 constructor 프로퍼티다.
//   ► __proto__: Object

console.log(Rectangle.prototype.__proto__);
// ▼ {move: ƒ, constructor: ƒ}
//   ► move: ƒ (x, y)
//   ► constructor: ƒ Shape()
//   ► __proto__: Object
 

2. Object.create() 없이 prototype 객체를 연결하면?

// Object.create()를 사용하지 않고 바로 할당했다.
Rectangle.prototype = Shape.prototype;

console.log(Rectangle.prototype);
// ► {move: ƒ, constructor: ƒ}   -> Shape 프로토객체의 move 메소드가 잘 보인다.
  • Object.create() 없이 바로 할당하면,
    Rectangle의 프로토타입 객체에 Shape 프로토타입 객체가 보인다.
    즉, Shape 프로토타입 객체의 Move 메소드가 보인다!

그래서 별 문제 없지않나, Object.create()을 사용한거랑 무슨 차이일까? 라는 생각이 들었다.

// Reactangle의 프로토타입 객체의 constructor 프로퍼티가 Shape로 연결되어 있다.
console.log(Rectangle.prototype.constructor);
// ► ƒ Shape() {   -> Shape가 나온다.
//     this.x = 0;
//     this.y = 0;
//   }

//다시 재할당해야지. Rectangle 프로토타입 객체의 constructor는 자신을 생성한 Rectangle이니까!
Rectangle.prototype.constructor = Rectangle;

//console.log로 확인하면 Rectangle로 잘 할당되어 있다.
console.log(Rectangle.prototype.constructor);
// ► ƒ Rectangle() {   -> 오! Rectangle이 잘 나온다. 
//     Shape.call(this);
//   }

//문제는 Shape의 프로토타입 객체의 constructor 프로퍼티도 Rectangle 함수로 바뀐다.
console.log(Shape.prototype.constructor)
// ► ƒ Rectangle() {   -> Shape가 나와야한다..ㅠㅠ 위에서 할당했으니 바뀔 수 밖에...
//      Shape.call(this);
//   }
  • Object.create()을 사용하지 않으면,
    Rectangle 프로토타입 객체constructor 프로퍼티
    Rectangle 생성자 함수 가 아닌 Shape 생성자 함수 를 참조한다.
    즉, Ractangle 생성자함수로 새로운 인스턴스를 만들게 되면,
    Shape 생성자함수로 새로운 객체가 만들어진다.

  • 이 문제를 해결하기 위해 Rectangle 생성자함수재 할당 을 한다.
    그러면 "Shape 프로토타입 객체" 의 constructor 프로퍼티
    Shape 생성자함수 가 아닌 Rectangle 생성자함수 를 가리키게 된다.
    즉, Shape 생성자함수로 새로운 인스턴스를 만들면,
    Rectangle 생성자함수로 새로운 객체가 만들어진다.

정리하면,
자바스크립트 언어는 상속을 통해 부모 객체의 기능을 물려받고,
본인만의 새로운 기능을 추가할 수 있다.
이러한 상속의 기능을 제대로 구현하기 위해서는 Object.create()를 활용 해야 한다!

잘못된 내용이 있다면 댓글로 알려주세요 :)

profile
꾸준히, 끄적끄적 해볼게요 :)

0개의 댓글