자바스크립트 객체
- 객체는 언제나 함수(Function)로 생성된다.
- 모든 객체는 프로토타입 링크(__proto__)를 가지고 있다.
- 프로토타입 링크(__proto__)는 객체가 생성될 때 부모 함수의 프로토타입 객체(Prototype Object)를 가리킨다.
자바스크립트 함수
- 함수 선언 시, 해당 함수에 생성자(Constructor) 자격 부여 및 프로토타입 객체가 생성된다.
-> 생성자(Constructor) 자격이 부여되면 new 키워드를 통해 객체를 만들어 낼 수 있다.
생성자(Constructor)가 아니면 new 키워드 사용불가. (함수만 new 키워드를 사용할 수 있는 이유)
new 키워드 사용 시, 해당 함수는 생성자 함수로 동작한다.
- 함수만이 프로토타입 속성(Prototype)을 가진다.
-> 프로토타입 속성(Prototype)을 통해 해당 함수의 프로토타입 객체에 접근할 수 있다.
위의 두 가지 사실에 기반하여 프로토타입을 알아보자.
프로토타입이란 무엇인가?
- 프로토타입의 사전적 의미는 "본격적인 상품화에 앞서 성능을 검증ㆍ개선하기 위해 핵심 기능만 넣어 제작한 기본 모델"이라고 정의되어 있다.
- 자바스크립트는 프로토타입 기반 언어(prototype-based language).
-> 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(Prototype Object)를 가진다는 의미.
-> ES2015부터 class 키워드를 지원하기 시작했으나, 문법적인 양념일 뿐이며 자바스크립트는 객체지향 언어가 아니라 여전히 프로토타입 기반의 언어.
- 프로토타입 링크, 프로토타입 객체 모두를 의미한다.
즉, 자바스크립트 객체의 기반이 되는 템플릿. 이를 프로토타입이라고 볼 수 있다.
프로토타입을 사용하는 이유로는
- 생성자 함수로 생성된 객체 모두에 프로퍼티, 메서드를 공유할 수 있다.
- 상속을 구현할 수 있다.
만약, 객체에 새로운 속성이 추가된다고 가정해보자.
각각의 객체마다 해당 속성을 추가하는 것은 메모리 낭비가 될 수 있다.
자바스크립트는 프로토타입 기반 언어라고 하였다. 모든 함수는 프로토타입 객체를 가지고 있으며 어떠한 함수로 생성된 객체들은 생성된 부모 함수의 프로토타입 객체를 참조하고 있다. 이러한 특성을 이용하여 함수의 프로토타입 객체만 수정하여 생성된 객체 모두에게 속성을 추가하는 효과를 얻을 수 있다.
프로토타입 객체
- 함수 선언 시, 함수와 같이 생성되는 객체이다.
- 기본적인 속성으로 생성자(Constructor)와 프로토타입 링크(__proto__)를 가지고 있다.
-> 함수 또한 객체이다.
- 생성자(Constructor)는 프로토타입 객체(Prototype Object)와 같이 생성되었던 함수를 가리킨다.
- 일반적인 방식으로는 속성은 생성자 함수에서, 메소드는 프로토타입 객체에 정의한다.
프로토타입 체인
- 프로토타입 객체는 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지. (최상위 프로토타입은 Object)
이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간이다.
객체 상속
자바스크립트에서 상속은 상위 함수의 속성뿐만아니라 프로토타입 객체까지 고려해야한다.
- Function.prototype.call()
-> 이미 할당되어있는 다른 객체의 함수/메소드를 호출하는 객체에 재할당할때 사용되며, 다른 곳에서 정의된 함수를 현재 컨텍스트에서 실행할 수 있도록 할 수 있다.
- 상속 사용 시기
-> 동일한 기능을 가진 클래스가 많아졌음을 발견했다면 기능들을 한데 묶어 공유할 수 있도록 일반 객체를 만들고 특이 객체들에게 상속한다.
아래 코드를 통해 위의 전체적인 내용을 정리하고자 한다.
function Person(first, last, age){
this.first = first;
this.last = last;
this.age = age;
}
Person.prototype.printAge = function() {
console.log("Person : "+ this.age);
}
//Person 상속
function Teacher(first, last, age, interests, subject){
Person.call(this, first, last, age);
this.interests = interests;
this.subject = subject;
}
//call()만 사용한 경우, Person의 프로토타입 속성이 없다. 단지 Person의 속성만 상속받은 것
//Teacher 함수는 아직 상속을 덜 받은 상태. 프로토타입 상속 필요
//Person 프로토타입 객체를 프로토타입으로 가지도록 설정한다. Object의 create()는 인자를 프로토타입으로 가지는 객체를 생성한다.
Teacher.prototype = Object.create(Person.prototype);
//Teacher 함수의 prototype은 Person 프로토타입 상속 받은상태. 하지만 Person 프로토타입 객체를 그대로 가지고 있기 때문에 생성자 함수 수정이 필요하다.
Teacher.prototype.constructor = Teacher;
Teacher.prototype.greeting = function(){
console.log("Hello");
}
var person = new Person("first", "last", 25);
var teacher = new Teacher("first", "last", 40, ["a","b", "c"], "subject");
person.printAge();
teacher.printAge(); //프로토타입 체인 발생
console.log(person);
console.log(teacher);
console.log(Person.prototype);
console.log(Teacher.prototype);
먼저, 부모 함수인 Person을 선언하자.
Person 함수는 first, last, age라는 속성과 printAge라는 메소드를 가지고 있다.
아래의 Teacher 함수는 Person 함수를 상속받는 함수이다.
함수 객체의 프로토타입에 있는 call() 메소드를 사용하여 Teacher 함수에 부모 함수의 속성들이 실행될 수 있도록 하고 추가적으로 가지는 속성 interests, subject 들을 정의하고 있다.
call() 메소드만 사용해서 상속을 끝낸다면 단순히 부모의 속성들만 받은것과 같다.
부모의 프로토타입(prototype)은 전혀 상속받지 않은 상태이며 상속이 제대로 되지 않았다고 할 수 있다.
따라서 Teacher 함수의 프로토타입도 상속을 받도록 처리가 필요하다.
Object 객체의 create() 메소드는 받은 인자를 프로토타입으로 가지는 객체를 생성하는 함수이다.
Person 함수의 프로토타입 객체를 프로토타입으로 가지는 객체를 생성하여 Teacher 함수의 프로토타입에 할당하면 프로토타입 객체또한 상속을 받은 상태라고 볼 수 있다.
하지만 Person 프로토타입 객체의 생성자(Constructor)는 Person이기 때문에 그것을 토대로 객체를 생성한 Teacher 프로토타입 객체는 수정이 필요하다. Teacher 프로토타입 객체의 생성자를 Teacher 함수로 수정해주면 최종적으로 상속은 완료된다.
최종적인 모습은 아래와 같다.
Person 생성자 함수로 생성된 객체는 프로토타입 링크(__proto__)로 Person 프로토타입 객체를 가리키고 있다.
Teacher 생성자 함수로 생성된 객체는 부모 함수(Person)의 속성을 모두 가지고 있으며 프로토타입 링크(__proto__)로
Teacher 프로토타입 객체를 가리키고 있으며 Teacher 프로토타입 객체의 프로토타입 링크는 부모 함수(Person)의 프로토타입 객체를 가리키고 있다.
또한 teacher.printAge() 부분이 Teacher 프로토타입 객체에는 존재하지 않지만 프로토타입 링크를 통해서 부모 함수(Person)의 프로토타입 객체에서 해당 메소드를 상속받아 정상적으로 40이 출력됨을 확인할 수 있다.
이는 프로토타입 체인이 동작한다는 증거이다.
[참고자료]
MDN WEB DOCS - Inheritance and the prototype chain
MDN WEB DOCS - Function.prototype.call()
MDN WEB DOCS - Object prototypes
Javascript 기초 - Object prototype 이해하기
JavaScript : 프로토타입(prototype) 이해