프로토타입은 특정 객체에 대한 참조를 의미합니다.
생성자 함수가 인스턴스를 생성하면 그 안에는 숨겨진 프로퍼티[[prototype]]
이 존재합니다.
코드에서는__proto__
로 표현됩니다.
__proto__
는 자신을 만든 생성자 함수의prototype
을 참조하는 역할을 합니다.
new 키워드를 통해 생성자 함수의prototype
과 인스턴스__proto__
가 연결됨을 의미합니다.
아래 예시 코드를 살펴봅시다.
function Person(name) {
this.name = name;
function introduce() {
console.log(`제 이름은 ${this.name}입니다.`);
}
}
const person1 = new Person('jon');
person1.__proto__ === Person.prototype // true;
위 코드에서 person 이라는 생성자 함수를 생성하고,
생성자 함수를 통해 person1이라는 인스턴스 객체를 만듭니다.
이후, person1의__proto__
가 person 생성자함수의prototype
임을 확인하기 위해 값이 같은지 확인하고 있습니다.
위에서 말 하였듯__proto__
는 자신을 만든prototype
생성자 함수를 참조한다고 하였습니다.
결과를 확인해 보면 true가 나오는 것을 알 수 있습니다.
자바스크립트에는 모든 객체에는 prototype이 존재합니다.
아래 예시 코드를 살펴봅시다.
const obj = {};
const array = [];
const func = function() {};
const str = new String('');
const map = new Map();
console.log(obj.__proto__ === Object.prototype);
console.log(array.__proto__.__proto__ === Object.prototype);
console.log(func.__proto__.__proto__ === Object.prototype);
console.log(str.__proto__.__proto__ === Object.prototype);
console.log(map.__proto__.__proto__ === Object.prototype);
빈 객체, 빈 배열, 함수 모두 거슬러
[[prototype]]
를 확인해 보면[[prototype]] : object
인 것을 확인 할 수 있습니다.
즉, 모든 객체는__proto__
는 object의 prototype를 참조한다는 것을 알 수 있습니다.이렇게, object를 조상으로 prototype으로 상속이 이루어지는 것을 프로토타입 체인이라고 합니다.
프로토 타입 체인으로 특정 객체에 호출된 프로퍼티가 없다면 프로토타입을 거슬러 올라가 프로퍼티를 찾게됩니다.
즉, 자신이 가지고 있지 않는 프로퍼티는 프로토타입을 통해 상속 받아 사용할 수 있게 됩니다.
위 그림과 같이 "ABC" 처럼 문자열에서도 prtotype 체인으로 상속이 이루어져 있기 때문에 String의 프로퍼티들과 Object의 프로퍼티들을 추가적으로 사용할 수 있습니다.
Array와 Map 마찬가지로 prtotype 체인으로 상속이 이루어져 있다는 것을 알 수 있습니다.
예시 코드를 통해 프로토타입 상속을 살펴보겠습니다.
function Animal(name, eat) {
this.name = name;
this.eat = eat;
}
Animal.prototype.introduce = function() {
console.log(`내 이름은 ${this.name} ${this.eat}동물이지!`)
}
function Eagle(name, eat) {
this.name = name;
this.eat = eat;
}
// 상속을 먼저 받은 후 자신의 프로토타입을 작성해야함
Eagle.prototype = Object.create(Animal.prototype);
Eagle.prototype.fly = function() {
console.log('날아서 이동중...');
}
const lion = new Animal('사자', '육식');
const eagle = new Eagle('독수리', '육식');
console.log(lion);
console.log(eagle);
Animal, Eagle 생성자 함수를 만들고, Eagle 생성자 함수의 프로토타입에 Obejcet.create() 메소드를 사용하여 AnimalPrototype를 상속 합니다.
프로토타입 상속시에는 상속을 먼저 받은 후 자신의 프로토타입을 작성해야 합니다.
👉 자신의 프로토타입을 먼저 작성하고 상속을 받으면 기존의 작성한 프로토타입은 상속 받은 프로토타입에 덮어쓰여 지기 때문입니다.
생성자 함수로 만든 인스턴스는 계속 새로 만들어 집니다.
이에 비해 프로토타입의 프로토퍼티는 새로 만들어지지않고 프로토타입을 참조 하게 됩니다.
따라서 인스턴스 보다 프로토타입을 사용하는 것이 전체 메모리 절약에 유용합니다.
즉, 각각의 공통된 프로퍼티들은 인스턴스로 생성하는 것 보다 프로토타입으로 생성하는것이 메모리 절약 측면에서 유리하다고 볼 수 있습니다.
아래 공통된 기능을 프로토타입으로 생성하는 예시를 살펴봅시다.
function Robot(name) {
this.name = name;
}
robot.prototype.sayName = function(){
console.log(`삐리리 제 이름 ${this.name}로봇 입니다.`);
}
const robot1 = new Robot('깡통');
const robot2 = new Robot('고철');
robot1.sayName();
robot2.sayName();
console.log(robot1.__proto__);
console.log(robot2.__proto__);
생성자 함수로 Robot를 생성하고, name을 인자로 받아 각각의 인스턴스 객체를 생성하고, 공통된 sayName은 프로토타입으로 생성합니다.
생성한 인스턴스의 sayName를 실행해 보면 모두 실행되고,__proto__
안에 sayName이 존재한다는 것을 알 수 있습니다.
현재 __proto__
는 사라질 기능으로, 사용 권장되지 않습니다.
대신 Object.getPrototypeOf()
, Object.setPrototypeof()
사용으로 대체될 수 있습니다.
📌 MDN 문서