객체지향 프로그래밍은 명령형 프로그래밍의 절차지향에서 벗어나 다양한 객체의 집합으로 프로그램을 표현한 것이다.
속성(attibue/property)은 특징이나 성질을 나타내는데, 이중 내가 구현하고자 하는 프로그램에 필요한 속성만 간추리는것을 추상화(abstraction) 라고한다.
객체(Object)는속성을 통해 여러개의 값으로 하나의 단위를 구성한 복합적인 자료구조이다.
상속은 객체지향에 있어 핵심 개념이다. 상속이란 어떤 객체의 프로퍼티 또는 메소드를 다른 객체가 상속받아 그대로 사용할 수 있는것을 말한다.
이를 이용해 자바스크립트에서는 불필요한 중복을 제거한다.
function Circle(radius){
this.radius = radius;
this.getArea = function(){
return Math.PI * radius ** 2;
}
}
위의 생성자함수 Circle을 보면 인자를 매개변수 radius로 받고 getArea메소드를 통해 return되는것을 볼 수 있다. 하지만 이는 매번 생성자함수 Circle을 선언할 때 마다 getArea메소드가 계속 선언되고 그로인해 getArea메소드가 계속 중복생성 되기에 이는 바람직하지 못하다.
이때 사용할 수 있는것이 프로토타입이다.
function Circle(radius){
this.radius = radius;
}
Circle.prototype.getArea = function(){
return Math.PI * radius. ** 2;
}
위와 같이 선언하게되면 getArea는 Circle한테 상속되었기 때문에 Circle 생성자 함수로 생성된 모든 인스턴스들은 Circle에 상속된 getArea를 사용 할 수 있게된다. 이로인해 메소드가 계속 중복생성되는 현상을 막을 수 있다.
프로토 타입 객체는 객체간 상속을 구현하기위해 사용된다.
모든 객체들은 [[Prototype]]이라는 내부 슬롯을 가지고, 모두 프로토타입을 갖고 있기에 모든 프로토타입들은 생성자함수와 연결되어있다.
그러나 내부 슬롯은 직접 들여다 보진 못하고 __proto__
접근자 프로퍼티를 통하여 간접적으로 접근할 수 있다.
모든 객체들은 __proto__
를 가지고 있는데 이는 객체들이 가지고있는게 아니라 모든객체이 상속받는 Object.prototype 의 프로퍼티이기에 객체들이 상속받아 사용할 수 있는것이다.
prototype이라는 프로퍼티는 함수객체만이 가질 수 있다. 일반객체는 prototype프로퍼티를 가질 수 없다. 그 이유로는 prototype프로퍼티는 생성자 함수가 생성할 인스턴스를 가리키기때문이다.
또한 Object.prototype으로부터 상속받은 __proto__
와 prototype프로퍼티는 결국 동일한 프로토타입을 가리킨다. 그러나 사용하는 주체가 틀리기에 혼용하는 일은 없게해야한다.
모든 프로토타입은 constructor라는 프로퍼티를 갖는다. constructor프로퍼티는 자신을 참조하고있는 생성자 함수를 가리킨다.
위의 프로토타입 객체에서 모든 프로토타입은 constructor라는 프로퍼티를 갖고 해당 프로퍼티는 자신을 참조하고있는 생성자 함수를 가리킨다고 했다. 그런데 리터럴 표기법으로 생성된 객체는 생성자 함수를 통하지 않고 생성된 객체인데 과연 이들의 constructor프로퍼티도 자신을 참조하고있는 생성자 함수를 가리키고 있을까?
정답은 그렇기도하고 아니기도하다.
만약 내가 리터럴 표기법을 이용하여 빈객체를 생성하였다고 하자. 그럼 해당 객체는 리터럴 표기법을 따랐고 생성자 함수 없이 생성되었는데 constructor프로퍼티가 무엇을 가리키는지 확인해보자.
const obj = {};
console.log(obj.constructor === 'Object'); // true
위와같이 obj의 생성자 함수는 Object 생성자 함수인것을 볼 수 있다. 이는 무엇을뜻하는가 하면 리터럴 표기법으로 생성된 객체 또한 Object생성자 함수를 따른다는것이다.
이는 ECMAScript를 살펴보면 알 수 있다. 인수가 전달되지 않았을 경우 추상연산(OrdinaryObjectCreate : ECMAScript에서의 내부 동작의 구현 알고리즘을 표현한것.)을 호출하여 Object.prototype을 프로토타입으로 갖는 빈 객체를 생성한다.
이를 통해 리터럴 표기법에 의해 생성된 객체라 할지라도 상속을 위해 프로토타입이 필요하다는것을 알 수 있다. 이는 곧 프로토타입과 생성자함수는 단독으로 존재할 수 없고 항상 쌍으로 존재한다는것이다.