자바스크립트를 공부하면서 가장 진입장벽이 높은 개념인 프로토타입,, 🤪
하나하나 차근차근 살펴보기!
자바스크립트는 프로토타입 기반 언어이다.
클래스 기반 언어에서는 상속을 사용하지만 프로토타입 기반 언어에서는 어떤 객체를 원형으로 삼고 이를 복제함으로써 상속과 비슷한 효과를 얻는다.
Prototype은 말 그대로 객체의 원형이라고 할 수 있다. prototype이라는 프로퍼티는 그 용도가 약속되어 있는 특수한 프로퍼티다. prototype에 저장된 속성들은 생성자를 통해서 객체가 만들어질 때 그 객체에 연결된다.
어떤 생성자 함수를 new 연산자와 함께 호출하면 constructor에 정의된 내용을 바탕으로 새로운 인스턴스가 생성된다. 이때 인스턴스에는 __proto__
라는 프로퍼티가 자동으로 부여되는데 이 프로퍼티는 constructor의 prototype이라는 프로퍼티를 참조한다.
예를 들어서 살펴보자!
Dog라는 함수를 만들고, Dog에 bark라는 prototype 속성을 추가해주었다.
function Dog(){}
Dog.prototype.bark = 'bow wow';
new 연산자를 통해 인스턴스를 생성했다.
const bori = new Dog();
bori를 호출해보면, __proto__
라는 프로퍼티와 bark속성이 부여되어있다.
function Animal(){}
Animal.prototype.bark = true;
function Dog(){}
Dog.prototype = new Animal();
function SmallDog(){}
SmallDog.prototype = new Dog();
const bori = new SmallDog();
console.log(bori.bark); //true
생성자 SmallDog을 통해 만들어진 객체 bori가 Animal의 프로퍼티 bark에 접근 가능한 것은 prototype 체인으로 SmallDog과 Animal이 연결되어 있기 때문이다. 내부적으로는 아래와 같은 일이 일어난다.
- 객체 bori에서 bark를 찾는다.
- 없다면 SmallDog.prototype.bark를 찾는다.
- 없다면 Dog.prototype.bark를 찾는다.
- 없다면 Animal.prototype.bark를 찾는다.
만약, bori와 SmallDog의 bark속성을 변경하면 어떻게 될까?
function Animal(){}
Animal.prototype.bark = true;
function Dog(){}
Dog.prototype = new Animal();
function SmallDog(){}
SmallDog.prototype = new Dog();
SmallDog.prototype.bark = 'wal wal';
const bori = new SmallDog();
bori.bark = 'bow wow';
console.log(bori.bark); //bowwow
prototype는 객체와 객체를 연결하는 체인의 역할을 한다.
이러한 관계를prototype chain
이라고 한다.
만약!! SmallDog.prototype = Animal.prototype 으로 한 후,
SmallDog의 bark 값을 변경하면 어떻게 될까?
function Animal(){}
Animal.prototype.bark = true;
function Dog(){}
Dog.prototype = Animal.prototype;
function SmallDog(){}
SmallDog.prototype = Animal.prototype;
SmallDog.prototype.bark = 'bow wooooow';
const bori = new SmallDog();
SmallDog.prototype = Animal.prototype 으로 하면 안된다. SmallDog.prototype의 값을 변경하면 Animal.prototype도 변경하기 때문이다.
Dog.prototype = new Animal()
은 Animal.prototype의 원형으로 하는 객체가 생성되기 때문에 new Animal()를 통해서 만들어진 객체에 변화가 생겨도 Animal.prototype의 객체에는 영향을 주지 않는다.
es6부터 Class 문법이 추가되었다.
그렇다고 자바스크립트가 프로토타입 기반 언어에서 클래스 기반 언어가 된 것은 아니다.
Prototype에서 상속을 구현하고자 한다면 앞서 설명했던 prototype chaining을 사용해야한다. 그렇지만 class를 사용하면 객체 생성자로 구현했던 코드를 조금 더 명확하게 구현 할 수 있고 상속도 훨씬 쉽게 해줄 수 있기 때문에 class를 사용하면 굳이
prototype chaining 을 써야할 필요가 없다.
class는 '틀' 과 같아서 도중에 바뀌는 일이 없다. 같은 틀 안에서 찍어낸 인스턴스를 프로퍼티나 메소드를 추가 하지 않는 이상 동일한 형태를 가진다.
반면 prototype 기반 언어는 객체가 곧 설계도가 되기 때문에 동적인 설계가 가능하다.