자바스크립트 객체는 **[[prototype]]**
이라는 숨김 프로퍼티를 갖는다. 이 값은 null
이거나 다른 객체
를 참조하는데, 다른 객체를 참조하는 경우 참조 대상을 **프로토타입**
이라 부른다.
객체에서 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 없으면 자바스크립트는 자동으로 포로토타입에서 프로퍼티를 찾는다.
**[[prototype]]
** 는 숨김 프로퍼티이면서 내부 프로퍼티이지만 개발자가 다양한 방법을 사용해 값을 설정할 수 있다.
__proto__
는 [[Prototype]]
용 getter·setter이다.
let animal = {
eats: true
};
let rabbit = {
jumps: true
};
rabbit.__proto__ = animal;
최근에는 Object.getPrototypeOf
나 Object.setPrototypeOf
를 쓰는 방법을 더 선호한다.
this는 프로토타입에 영향을 받지 않는다.
// animal엔 다양한 메서드가 있습니다.
let animal = {
walk() {
if (!this.isSleeping) {
alert(`동물이 걸어갑니다.`);
}
},
sleep() {
this.isSleeping = true;
}
};
let rabbit = {
name: "하얀 토끼",
__proto__: animal
};
// rabbit의 프로퍼티 isSleeping을 true로 변경합니다.
rabbit.sleep();
alert(rabbit.isSleeping); // ??
alert(animal.isSleeping); // ??
for...in 반복문은 상속 프로퍼티도 순회 대상에 포함시킨다.
대신 obj.hasOwnProperty(key)
를 이용하면 상속 프로퍼티를 순회 대상에서 제외할 수 있다.
let animal = {
eats: true
};
let rabbit = {
jumps: true,
__proto__: animal
};
for(let prop in rabbit) {
let isOwn = rabbit.hasOwnProperty(prop);
if (isOwn) {
alert(`객체 자신의 프로퍼티: ${prop}`); // 객체 자신의 프로퍼티: jumps
} else {
alert(`상속 프로퍼티: ${prop}`); // 상속 프로퍼티: eats
}
}
위에서 rabbit을 for ... in을 사용해서 반복문을 돌 때 prop에 hasOwnProperty가 들어갈까?
생성자 함수에 prototype 프로퍼티가 있고 그것이 객체이면 생성자 함수 안에서 만드는 객체의 프로토타입을 prototype 프로퍼티를 이용해서 설정한다.
function sum(a,b){
// prototype : {constructor: sum}
}
모든 함수는 prototype 프로퍼티를 갖는다. 기본 프로퍼티인 "prototype"은 constructor 프로퍼티 하나만 있는 객체를 가리키는데 constructor 프로퍼티는 함수 자기 자신을 가리킨다.
constructor 프로퍼티를 이용해서 새로운 객체를 만들 수 있다.
function Rabbit(name) {
this.name = name;
alert(name);
}
Rabbit.prototype = {}
let rabbit = new Rabbit("White Rabbit");
let rabbit2 = new rabbit.constructor("Black Rabbit");
그런데 prototype 프로퍼티에 항상 contstructor가 있도록 자바스크립트가 보장을 해주지는 않는다.
따라서 prototype에 다른 객체를 덮어쓰는 것 보다 prototype에 다른 프로퍼티를 추가하는 것이 좋다.
function Rabbit() {}
// Rabbit.prototype 전체를 덮어쓰지 말고
// 원하는 프로퍼티는 그냥 추가하세요.
Rabbit.prototype.jumps = true
// 이렇게 하면 기본 Rabbit.prototype.constructor가 유지됩니다.
proto는 구식이기 때문에 더 사용하는 것을 권장하지 않는다.
대신 아래와 같은 메서드를 사용하는 것이 좋다.
[[Prototype]]
이 proto
를 참조하는 빈 객체를 만듭니다. 이때 프로퍼티 설명자를 추가로 넘길 수 있습니다.obj
의 [[Prototype]]
을 반환합니다.obj
의 [[Prototype]]
이 proto
가 되도록 설정합니다.Object.create()로 객체를 만들면 proto getter와 setter를 상속 받지 않는다.
let animal = {
eats: true
};
// 프로토타입이 animal인 새로운 객체를 생성합니다.
let rabbit = Object.create(animal);
alert(rabbit.eats); // true
alert(Object.getPrototypeOf(rabbit) === animal); // true
Object.setPrototypeOf(rabbit, {}); // rabbit의 프로토타입을 {}으로 바꿉니다.