자바스크립트의 객체는 프로토타입을 상속하여 기능을 확장합니다.
객체가 가지는 [[Prototype]] 이라는 숨김 프로퍼티는 다른 객체에 대한 참조나 null 값을 갖습니다.
[[Prototype]] 이 다른 객체를 참조할 때, 그 참조 대상을 프로토타입 이라고 합니다.
프로토타입을 지정하지 않아도 객체 리터럴 문법으로 객체를 생성하면 [[Prototype]] 이 Object 인 걸 확인할 수 있습니다.
객체는 자동으로 Object.prototype 을 상속받아 기능을 사용합니다.
프로토타입을 따로 지정하면, 상속 받은 객체는 프로토타입의
프로퍼티와 메서드를 사용할 수 있습니다.
객체는 자신에게 없는 프로퍼티를 참조하면, 프로토타입을 탐색하여 찾습니다.
프로토타입에는 다음과 같은 특징이 있습니다.
__proto__ 로 프로토타입 지정__proto__ 는 [[Prototype]] 을 위한 getter-setter__proto__ 에는 null 이나 객체만 올 수 있음(다른 값은 무시)__proto__ 로 프로토타입 객체의 속성을 변경할 수는 ❌다음과 같이, __proto__ 속성에 프로토타입으로 사용할 객체를 지정해줌으로서 프로토타입의 기능을 사용할 수 있습니다.
let animal = {
eats: true
};
let rabbit = {
jumps: true
// 아니면 여기에 직접
// __proto__: animal
};
rabbit.__proto__ = animal; // (*)
// 프로퍼티 eats과 jumps를 rabbit에서도 사용
alert( rabbit.eats ); // true (**)
alert( rabbit.jumps ); // true

rabbit 객체는 animal 객체를 상속받고, animal 은 Object.prototype 을 상속받고 있습니다.
rabbit.hasOwnProperty(key) 를 사용하면 다음과 같은 순서로 탐색합니다.
rabbit 자기 자신 탐색animal 탐색Object 탐색이처럼... 상속 체인을 올라가며 탐색합니다. 같은 이름의 프로퍼티가 존재하면 가장 가까운 위치의 프로퍼티를 사용하게 됩니다.
this 는 어디서 호출하든 언제나 . 앞의 객체를 가리킵니다.
상속 받은 프로토타입의 메서드에서 this 를 사용해도, 이는 프로토타입이 아니라 메서드를 호출한 객체 자기 자신을 가리킵니다.
let animal = {
walk() {
if (!this.isSleeping) {
alert(`동물이 걸어갑니다.`);
}
},
sleep() {
this.isSleeping = true;
}
};
let rabbit = {
name: "하얀 토끼",
__proto__: animal
};
// rabbit에 새로운 프로퍼티 isSleeping을 추가하고 그 값을 true로 변경
rabbit.sleep();
alert(rabbit.isSleeping); // true
alert(animal.isSleeping); // undefined (프로토타입에는 isSleeping이라는 프로퍼티가 없음)
메서드는 공유하여 사용할 수 있지만 객체의 상태는 공유하지 않습니다.
for..in 을 이용해서 객체의 프로퍼티를 순회할 때, 객체 자신의 프로퍼티와 상속 프로퍼티 모두를 포함합니다.
이를 필터링하기 위해, obj.hasOwnProperty(key) 를 사용합니다.
obj.hasOwnProperty(key);
obj: 객체key: 프로퍼티 키true, 아니면(없거나, 프로토타입에만 있거나) falselet 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
}
}
모든 함수는 기본적으로 prototype 이라는 일반 프로퍼티를 가지며, Function.prototype 은 함수 Function 의 프로토타입을 의미합니다.
이 Function.prototype 은 new Function 문법으로 객체를 생성할 때 활용됩니다.
생성자 함수의 프로토타입이 객체라면 new 연산자로 생성되는 객체의 [[prototype]] 은 생성자함수의 Function.prototype 을 참조합니다.
[[Prototype]] 이 생성자 함수의 prototype 프로퍼티 참조함수의 prototype 프로퍼티는 디폴트로 constructor 프로퍼티 하나만 존재하는 객체인
{constructor: Function} 를 가리킵니다.
이 때, constructor 는 함수 자신을 가리킵니다.
function Rabbit() {}
// 디폴트 prototype:
// Rabbit.prototype = { constructor: Rabbit }
let rabbit = new Rabbit(); // {constructor: Rabbit}을 상속받음
alert(rabbit.constructor == Rabbit); // true ([[Prototype]]을 거쳐 접근함)
생성자 함수로 만들어진 객체는 Rabbit.prototype 을 프로토타입으로 지정하여, 자신에게 없는 기능을 프로토타입에서 가져와 사용할 수 있습니다.
function Rabbit(){
this.name = "RR";
this.jump = true;
};
let rabbit = new Rabbit();
Rabbit.prototype.ears = "long"; // 프로토타입에 기능 확장
alert(rabbit.ears); // long
Rabbit.prototype 에 프로퍼티를 추가하자 rabbit 객체도 변화된 내용을 활용할 수 있습니다.
그러나, Rabbit.prototype 이 참조하는 대상 자체를 바꿔버리면, 즉 Rabbit.prototype 을 재할당하면 그 순간부터 rabbit 과 Rabbit.prototype 은 서로 별개의 존재가 됩니다.
서로 다른 두 대상을 가리키므로, 프로토타입의 변화가 영향을 미치지 않습니다.
Function.prototype 은 { constructor: Function } [[Prototype]] 은 생성자의 프로토타입에 대한 참조를 담고있음Function.prototype 의 프로퍼티에 [[Prototype]] 을 사용하여 접근Function.prototype 은 객체로, Object 에 의해 생성되죠.
따라서 따로 지정하지 않아도 모든 객체는 프로토타입 체인 최상위에 Object.prototype 을 가집니다.
Object.prototype 의 메서드를 사용하면 하위에서 따로 재정의하지 않는 한 그 메서드를 그대로 사용합니다.
Object 를 보면 함수라고 나오는데, 이 함수 자체가 가지는 프로퍼티가 많습니다.
이 중에 prototype 프로퍼티가 가리키는 객체가 생성자 함수 Object 로 만든 객체의 프로토타입이 되는거죠.
그 외에 Object 함수 자체의 프로퍼티는 인스턴스가 프로토타입 체이닝을 사용하여 참고할 수 없습니다.
그냥 Object.assign(...) 이렇게 함수의 메서드 형식으로 불러 인스턴스를 매개변수로 넘겨주는 방식으로 사용합니다.
함수명.프로퍼티 로 호출자바스크립트의 모든 내장 생성자 함수에서 prototype 프로퍼티를 사용할 수 있습니다.
객체 리터럴 문법 {} 는 new Object() 를 간단히 나타낸 것으로, 둘의 동작은 동일합니다.
따라서 일반적으로 생성된 모든 객체는 Object.prototype 을 상속받습니다.
Object.prototype 은 프로토타입 상속 트리 꼭대기에 위치하며, 다른 내장 객체들이 이를 상속받는 구조입니다.

Array.prototype.__proto__ === Object.prototype; // true
문자열, 숫자, 불린값 등 객체가 아닌 원시 타입에는 프로토타입이 없습니다.
그러나 이런 원시 타입의 프로퍼티에 접근하려 할 때 임시 래퍼 객체가 생성되며, 래퍼 객체의 프로토타입에 구현한 메서드를 사용하도록 규정합니다.
let str = "12345";
str.length; // 5
// 임시 래퍼 객체 String 생성
// String.prototype 에서 length 를 가져와 반환
이렇게 해서 원시 타입의 프로퍼티, 메서드 사용을 보장합니다.
다만 null 과 undefined 는 래퍼 객체가 없습니다.
__proto__ 는 구식 문법으로, 모던하게 프로토타입을 다루기 위한 메서드는 다음과 같습니다.
Object.create(proto, [descriptors]): [[Prototype]]이 proto 를 참조하는 빈 객체를 생성하여 반환. 이때 프로퍼티 설명자를 추가로 넘길 수 있음Object.getPrototypeOf(obj): obj 의 [[Prototype]]을 반환Object.setPrototypeOf(obj, proto): obj 의 [[Prototype]]이 proto 가 되도록 설정