시간의 흐름에 따라서 코드를 작성하는 절차적 프로그래밍이랑 반대되는 개념으로 모든 사물들을 객체로 표현하여 독립된 객체간의 소통으로 이루어진 프로그래밍이다.
자바스크립트에서는 클래스 기반의 객체지향 프로그래밍과는 다르게 프로토타입 기반의 객체지향 프로그래밍이 가능하며 상속을 구현하기 위해서 사용된다. 자바스크립트의 모든 객체는 자신의 부모 역할의 객체와 연결되어 있는데 이 부모 객체를 프로토타입이라 한다. 프로토타입에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공한다.
🔥 객체 생성방식에 따라서 프로토타입이 결정된다.
🔥 자바스크립트는 원시값을 제외한 나머지 값은 모두 객체이며 [[Prototype]] 내부슬롯을 가진다.
🔥 인스턴스는 [[Prototype]]의 constructor 프로퍼티를 통해 생성자 함수에 접근할 수 있다.
🔥 생성자 함수는 자신의 prototype 프로퍼티를 통해서 접근한다.
const car = {
name: "K5"
};
// 객체 car의 [[Prototype]]에 접근
console.log(car.__proto__);
🔥 자바스크립트 내부슬롯에 접근이 원칙적으로는 불가능하지만 간접적으로 접근할 수 있도록 방법을 제공한다.
const car = {
name: "K5"
};
const animal = {
name1: "Dog"
};
// 프로토타입을 교체함
car.__proto__ = animal;
// 결과 : Dog 출력
console.log(car.name1);
const car = {
name: "K5"
};
const animal = {
name: "Dog"
};
// 프로토타입을 교체함
car.__proto__ = animal;
// K5 출력
console.log(car.name);
// [[Prototype]]을 눌러서 확인하면 안에 name: "Dog" 프로퍼티를 확인할 수 있다.
console.log(car);
🔥 프로토타입 체인으로 인해 K5가 출력된다. car 객체 위에 animal이 상속되어 있는 형태라고 생각하면 편하다. 그래서 car부터 먼저 프로퍼티를 확인하기 때문에 K5가 출력된다. 하지만 [[Prototype]] 안에는 animal의 프로퍼티가 존재한다.
🔥 proto를 코드 내에서 직접 사용하는 것은 권장하지 않으며 접근 방법은 Object 메소드를 사용하면 된다.
🔥 Object.getPrototypeOf와 Object.setPrototypeOf()를 사용하면 된다.
✨ 상속은 class를 사용하는게 더 좋은것 같다. (내 생각)
함수객체는 생성자 함수로 사용할 수 있으므로 자체적으로 prototype 프로퍼티를 가진다. 즉 인스턴스의 프로토타입을 가리킨다.
객체의 프로퍼티에 접근 할려고 할 때 해당 객체에 프로퍼티가 없으면 [[Prototype]]을 따라서 부모에게 상속받은 것 처럼 프로퍼티를 순차적으로 검색하여 있으면 프로퍼티를 사용한다.
생성자 함수에서 prototype을 조작해서 생성자 함수가 생성하는 인스턴스에 상속이 가능하다.
function Car(name) {
this.carName = name;
}
// 프로토타입으로 추가
Car.prototype.log = function() {
console.log(this.carName);
}
// 생성자 함수로 인스턴스 생성
const car = new Car("K5");
// 출력 : K5
car.log();
// prototype 확인해보기
console.dir(car);
// Object 메소드를 프로토타입 체인에 의하여 사용가능
console.log(car.hasOwnProperty("carName"));
🔥 해당과정의 순서를 생각해보면 일단 Car라는 생성자 함수로 인스턴스인 car를 생성한다. 그러면 car라는 객체에 Car의 프로퍼티와 프로토타입이 상속되어 사용하게 된다. 그리고 프로토타입도 객체이기 때문에 Object.prototype를 가지게 된다. 그러므로 Object.prototype도 사용이 가능하다.
ES6 부터는 class의 extends를 이용하여 상속을 구현하지만 프로토타입을 이용해도 상속을 구현할 수 있다.
🧩 Object.create("프로토타입", [프로토타입 옵션])
객체를 생성할 수 있는 방법이다. 프로토타입을 지정해주면 객체가 생성된다.
// 프로토타입을 연결한뒤 key값이 key이며 value값이 value인 요소를 가진 객체를 생성한다.
const obj = Object.create(Object.prototype, {
key: {
value: "value"
}
});
// 결과 : { key: value }
console.log(obj.key);
🧩 프로토타입을 이용해서 상속구현
// A인 함수를 생성
function A() {}
// 생성자 함수로 사용하기 위해 prototype 메소드 생성
A.prototype.logA = function() {
console.log('A');
}
// A를 상속받을 B 함수를 생성
function B() {}
// B의 프로토타입을 A의 프로토타입을 가진 객체로 지정
B.prototype = Object.create(A.prototype);
// 현재 상태는 B의 constructor가 A를 가리킴 다시 B로 지정
B.prototype.constructor = B;
// B의 prototype 메소드 생성
B.prototype.logB = function() {
console.log('B');
}
// B를 상속받을 C 함수를 생성
function C() {}
// B가 A를 상속 받는코드와 똑같음
C.prototype = Object.create(B.prototype);
C.prototype.constructor = C;
C.prototype.logC = function() {
console.log('C');
}
// 인스턴스 생성
const c = new C();
// 결과 : C
c.logC();
// 결과 : B
c.logB();
// 결과 : A
c.logA();
🔥 프로토타입 체인을 따라가 상속받은 메소드들을 찾아서 출력한다.