2020년 1월, 바닐라코딩 7기 부트캠프를 다니고 있다.
앞으로 부트 캠프를 다니는 동안 배우는 것들을 조금씩, 그리고 꾸준히 끄적이려고 한다.
Object.create(proto[, propertiesObject])
지정된 프로토타입 객체 및 속성(property)을 갖는 새 객체를 만듭니다.
- proto
새로 만든 객체의 프로토타입이어야 할 객체.- propertiesObject
선택사항. 지정되고 undefined가 아니면,
자신의 속성(즉, 자체에 정의되어 그 프로토타입 체인에서 열거가능하지 않은 속성)이
열거 가능한 객체는 해당 속성명으로 새로 만든 객체에 추가될 속성 설명자(descriptor)를
지정합니다.
이러한 속성은Object.defineProperties()의 두 번째 인수에 해당합니다.
출처 MDN
Object.create()를 공부하면서 헷갈렸던 부분은 크게 2가지이다.
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(Rectangle.prototype);
// ▼ {constructor: ƒ}
// ► constructor: ƒ Rectangle() -> constructor 프로퍼티가 Rectangle 생성자함수를 가리키고 있다.
// ► __proto__: Object -> 프로토타입 체인으로 부모 객체와 연결된다.
console.log(Rectangle.prototype.__proto__);
// ▼ {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ …}
// ► constructor: ƒ Object()
// ► ....
([[prototype]]이 proto 와 같은거다!)
proto 혹은 [[prototype]]
- 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯이다.
- 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype를 가리킨다.
출처 Poiemaweb
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
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
// Object.create()를 사용하지 않고 바로 할당했다.
Rectangle.prototype = Shape.prototype;
console.log(Rectangle.prototype);
// ► {move: ƒ, constructor: ƒ} -> 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()를 활용 해야 한다!
잘못된 내용이 있다면 댓글로 알려주세요 :)