기존 객체에서 프로퍼티와 메서드를 상속 받아 유사한 역할을 하는 객체를 만들 수 있음
코드의 중복을 막고 재사용을 위해 주로 사용
부모 객체인 프로토타입을 동적으로 변경할 수 있음
객체에서 프로퍼티를 읽으려 할 때 객체 내에 해당 프로퍼티가 없으면 자바스크립트가 자동으로 프로토타입에서 프로퍼티를 찾는데, 이런 동작 방식을 '프로토타입 상속'이라고 함.
자바스크립트의 객체는 prototype이라는 숨겨진 프로퍼티를 갖는데
이 값은 null이지만 __proto__ 키워드를 사용해 값을 설정할 수 있고 다른 객체에 대한 참조가 가능하다.
다른 객체를 참조하는 경우 참조 대상을 '프로토타입'이라고 부른다.
[[Prototype]]
객체 내부에 숨겨져 있는 숨김 프로퍼티로 아래 메서드나 키워드를 사용해 값을 설정해서 다른 객체를 참조할 수 있음.
-
Object.create(proto, [descriptors])
[[Prototype]]이 proto를 참조하는 빈 객체를 생성. 이때 설명 첨부 가능.
// Object.create();
const drinkPrototype = {
order: function () {
return `주문한 음료는 ${this.name}입니다.`;
},
};
// 빈 객체를 생성하고 프로토타입 지정
const drink1 = Object.create(drinkPrototype);
console.log(drink1); // drinkPrototype을 참조했지만 아직 빈 배열이다.
drink1.name = "유자차"; // .표기법으로 name 프로퍼티 추가
console.log(drink1); // { name: 유자차 }
/*
drinkPrototype이 drink1의 프로토타입이기 때문에
drink1에 없는 메서드 order를 프로토타입 안에서 탐색하여 호출.
*/
console.log(drink1.order()); // 주문한 음료는 유자차입니다.
const drink2 = Object.create(drinkPrototype);
drink2.name = "생강차";
console.log(drink2.order()); // 주문한 음료는 생강차입니다.
drink1.order === drink2.order
? alert("drink1과 drink2는 같은 프로토타입을 가졌습니다")
: alert("drink1과 drink2는 다른 프로토타입을 가졌습니다.");
// drink1과 drink2의 [[Prototype]]이 같은 proto(drinkPrototype)를 참조하기에
//true의 값이 출력된다.
// 생성자 함수로 객체 생성
function coffee(name) {
return {
// 함수 내 객체
name, // 키와 값이 같은 프로퍼티는 하나로 생략 가능 === name: name,
order: function () {
return `주문한 음료는 ${this.name}입니다`;
},
};
}
const coffeeList = []; // 빈 배열 생성.
for (let i = 0; i < 5; i++) {
coffeeList.push(coffee("아메리카노"));
}
console.log(coffeeList) // 배열 내 {name: 아메리카노, order()} 5개 생성
console.log(coffeeList[0].order === coffeeList[1].order); // false
/* Object.create()로 프로토타입을 설정해 함수를 상속받는 건
동일한 메모리에 할당된 함수 값을 불러오는 것으로 상속 받은 객체가 달라도 true지만 */
/* 일반 함수를 사용해 배열 내에 객체를 단순 복사하는 것은
각 객체와 그 객체 내 각 함수가 각자의 메모리에 할당되는 것이라 false가 나온다. */
-
Object.getPrototypeOf(obj)
obj의 [[Prototype]]을 반환
-
Object.setPrototypeOf(obj, proto)
obj의 [[Prototype]]이 proto가 되도록 설정.
-
__proto__ 키워드
let potato = {
color: "brown",
}
let honey = {
flavor: "sweet",
}
console.log(honey.color); // undefined, honey 객체에 color 프로퍼티 없음.
honey.__proto__ = potato; // potato를 honey의 [[Prototype]]으로 설정.
console.log(honey.color);
// honey에는 color 프로퍼티가 없기 때문에 자바스크립트에서 자동으로
// [[Prototype]]이 참조하고 있는 객체 potato의 객체 내부에서 color를 읽어 옴.
=
'honey의 프로토타입은 potato'
=
'honey는 potato를 상속받는다.'
-
메서드도 상속 가능.
let IamProto = {
message: function () {
alert(`이 함수는 프로토타입에서 상속받았습니다.`)
}
}
let whoIsProto = {
alarm: function () {
alert(`이 함수는 객체 내 프로퍼티입니다.`)
}
}
whoIsProto.__proto__ = IamProto
// 객체 내 같은 이름의 키가 있으면
console.log(whoIsProto.message()); //이 함수는 프로토타입에서 상속받았습니다.
'프로토타입 체이닝'
-프로토타입에게 상속받는 프로토타입에게 상속받는 프로토타입에게 상속받는 프로토타입에게 상속받는 프로토타입...
1. 순환 참조는 허용되지 않음. __proto__를 작성해 닫힌 형태로 다른 객체를 참조하면 에러 발생.
2. __proto__의 값은 객체 혹은 null만 가능하며 다른 자료형은 무시된다.
3. 객체는 오직 하나의 [[Prototype]]만 있으며 두 개의 객체에서 상속받는 것은 불가능.
let IamProto = {
message: function () {
alert(`이 함수는 IamProto에서 상속받았습니다.`)
}
}
let whoIsProto = {
alarm: function () {
alert(`이 함수는 whoIsProto에서 상속받았습니다.`)
}
}
let heyProto = {
getMessage: function(){alert(`이 함수는 객체 내 메서드입니다.`)}
}
whoIsProto.__proto__ = IamProto
heyProto.__proto__ = whoIsProto
// 객체 내 같은 이름의 키가 있으면
console.log(heyProto.message()); //`이 함수는 IamProto에서 상속받았습니다.`
console.log(heyProto.alarm()); //`이 함수는 whoIsProto에서 상속받았습니다.`
console.log(heyProto.getMessage()); //`이 함수는 객체 내 메서드입니다.`
'프로토타입은 읽기 전용'
-
프로토타입은 프로퍼티를 읽을 때만 사용되며 프로퍼티를 추가, 수정, 삭제하는 것은 해당 객체에 직접 적용해야 함.
'JavaScript' 카테고리의 다른 글
[JavaScript] 배열의 메서드 종류_more (0) | 2022.12.07 |
---|---|
[JavaScript] 객체 프로퍼티 설정 (0) | 2022.12.06 |
[JavaScript] 배열 (array) (0) | 2022.12.06 |
[JavaScript] 구조 분해 할당 (0) | 2022.12.06 |
[JavaScript] Math 객체 (0) | 2022.12.05 |