[JS] 프로토타입기반 객체지향
자바스크립트는 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.
자바스크립트는 객체기반의 프로그래밍 언어이며 자바스크립트를 이루고 있는 거의 '모든 것' 이 객체이다. (원시타입의 값을 제외한 나머지 값은 모두 객체이다.)
객체지향 프로그램은 실세계의 실체를 인식하는 철학 사고를 바탕으로 프로그래밍을 하는 것인데,
여기서 실체를 객체 (Object)의 형태로 구현하며 실체가 가지는 여러가지 특징이나 성질을 객체 내 속성(Attribute/Property)로 구현한다.
추상화란 사람이라는 객체 내부에 '이름','주소'라는 속성을 개발자가 지정하여 필요한 속성만 간추려 내어 표현하는 것을 말한다.
const person = {
name: "Lee";
address: "Seoul";
};
객체 내에는 객체의 상태를 나타내는 데이터와 데이터를 조작할 수 있는 동작이 하나의 논리적 단위(객체)로 묶여있다. 상태 데이터를 프로퍼티(Property), 동작을 메서드(Method)라 부른다.
객체는 고유의 가능을 갖는 독립적인 부품으로 볼 수 있지만 다른 객체와 관계성 또한 가질 수 있다. 데이터를 처리하거나, 상태 데이터나 동작을 상속받아 사용하기도 한다.
상속과 프로토타입
상속(inheritance) -> 기존에 정의된 객체의 프로퍼티, 메소드를 다른 객체가 그대로 사용할 수 있다.
이는 불필요한 코드의 중복을 제거한다.
function Circle(radius) {
this.radius = radius;
this.getArea = function () {
return Math.PI * this.radius ** 2;
};
};
const circle1 = new Circle(1);
const circle2 = new Circle(2);
//Circle의 생성자 함수는 인스턴스를 생성할 때마다 동일한 동작을 하는
//getArea 메서드를 중복생성하고 모든 인스턴스가 중복 소유한다.
console.log(circle1.getArea === circle2.getArea); //false
console.log(circle1.getArea()); //3.141592...
console.log(circle2.getArea()); //12.566370...
위 코드를 통해 Circle 객체를 여러번 생성하면 생성 할 때마다 같은 동작을 하는 getArea는 circle의 각 객체마다 저장되어 메모리를 과도하게 잡아먹게 된다. 이러한 불필요한 낭비를 막기위해
객체보다 상위 객체를 만들어 (상속을 통해) 메서드를 불러오도록 동작하면 getArea에 대한 각 인스턴스 속 불필요한 저장공간을 줄일 수 있지 않을까?
라는 개념을 도입한 것이 프로토타입의 주요 존재 이유이다.
function Circle(radius) {
this.radius = radius;
};
Circle.prototype.getArea = function () {
return Math.PI * this.radius ** 2;
};
const circle1 = new Circle(1);
const circle2 = new Circle(2);
//Circle 생성자 함수가 생성한 모든 인스턴스는 부모 객체의 역할을 하는
//프로토타입 Circle.prototype으로부터 getArea 메서드를 상속받는다.
console.log(circle1.getArea === circle2.getArea); //true
console.log(circle1.getArea()); //3.141592...
console.log(circle2.getArea()); //12.566370...
Circle의 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입, 즉 상위 객체 역할을 하는 Circle.prototype의 모든 프로퍼티와 메서드를 상속받는다.
이를 통해 각각 인스턴스에게 필요한 고유한 데이터 프로퍼티는 개별적으로 보유하되, 같은 동작을 하는 메서드는 상속을 통해 프로토타입에서 꺼내 사용할 수 있다.
이는 메모리 관점에서도 매우 유용하며, 여러개의 인스턴스를 효율적으로 만들어 낼 수 있다.
프로토타입 객체
모든 객체는 [[Prototype]]이라는 내부 슬롯을 가지고 있으며, 이 내부 슬롯의 값은 프로토타입의 참조이다.
모든 객체는 하나의 프로토타입을 가지며, 객체 생성 방식에 따라 [[Prototype]]에 저장되는 프로토타입이 결정되게 된다. 모든 프로토타입은 생성자 함수와 연결되어 있다.
__proto__
접근자 프로퍼티
[[Prototype]] 내부 슬롯에는 직접적으로 접근할 수 없지만 __proto__
접근자 프로퍼티를 통해 간접적으로 접근할 수 있다.
__proto__
는 [[Prototype]]이라는 내부슬롯의 값에 접근할 수 있게 해주는 접근자 프로퍼티로 여느 다른 접근자 프로퍼티와 같이 [[Get]], [[Set]] 프로퍼티 어트리뷰트를 갖고 있다.
__proto__
를 값을 불러오는데 사용되면 getter 함수가 호출되어 객체의 프로토타입을 취득하며, 값을 할당하는데 사용되면 setter 함수가 호출되어 객체의 프로토타입을 교체한다.
const obj = {};
const parent = {x:1};
//get함수 호출 obj 객체의 프로토타입을 반환
obj.__proto__;
//set함수 호출 obj 객체의 프로토타입을 parent로 교체
obj.__proto__ = parent'
console.log(obj.x); //1
__proto__
는 객체가 직접 소유하는 프로퍼티가 아닌 Object.prototype의 프로퍼티이다. 모든 객체는 상속을 통해 Object.prototype.__proto__
접근자 프로퍼티를 사용할 수 있다.
Object.prototype
은 모든 객체가 묶여있는 계층구조, 프로토타입 체인의 최상위 종점에 위치하는 객체이며, 이 객체의 프로퍼티와 메서드는 모든 객체의 생성 즉시 상속된다.
(마치 모든 객체의 시조이자 근본 같은 뿌리)
__proto__
는 상호 참조로 인해서 프로토타입 체인이 루프에 빠져버리는 것을 방지하기 위해 사용된다. 상위 부모객체의 프로토타입이 자식객체로 지정되는 경우 프로토타입 체인이 꼬이게 되고 단방향 링크드 리스트로 구현되지 않는다. 순환참조로 이루어지면 프로토타입체인에서 프로퍼티를 검색할 때 무한루프에 빠지기 떄문에 __proto__
접근자 프로퍼티를 통해 프로토타입에 접근하고 교체하도록 구현되어 있다.
그런데 모든 객체가 Object.prototype을 상속받지 않기 때문에 __proto__
접근자 프로퍼티의 코드 내 사용을 권장하지는 않는다. __proto__
보다 프로토타입의 참조를 취득하고 싶은 경우 Object.getPrototypeOf
메서드 사용을 권장하고, 프로토타입을 교체하고 싶은 경우 Object.setPrototypeOf
메서드를 사용할 것을 권장한다. (IE11이상에서 지원한다.)
Author And Source
이 문제에 관하여([JS] 프로토타입기반 객체지향), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@rlatp1409/JS-프로토타입기반-객체지향저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)