19.1 객체지향 프로그래밍
- 객체(object)의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임
- 객체의 상태를 나타내는 데이터와 상태 데이터를 조작할 수 있는 동작을 하나의 논리적인 단위로 묶어서 생각하는 것
- 각 객체는 자신의 고유한 기능을 수행하면서 다른 객체와의 관계성(relationship)을 가질 수 있다.
- 프로퍼티(property)
: 객체의 상태 데이터
- 메서드 (method)
: 객체의 동작
추상화(abstraction)
- 다양한 속성 중에서 프로그램에 필요한 속성만 간추려 표현
ex) "이름"과 "주소"라는 속성을 갖는 person 객체
//이름과 주소 속성을 갖는 객체
const person = {
name : 'Lee',
address : 'Seoul'
};
console.log(person); //{ name: 'Lee', address: 'Seoul' }
19.2 상속과 프로토타입
- 상속(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);
console.log(circle1.getArea === circle2.gerArea); //false
console.log(circle1.getArea()); //3.141592653589793
console.log(circle2.getArea()); //12.566370614359172
- raidus 프로퍼티 값은 일반적으로 인스턴스마다 다름
- getArea 메서드는 모든 인스턴스가 동일한 내용의 메서드를 사용하므로 단 하나만 생성하여 모든 인스턴스가 공유해서 사용하는것이 바람직함
- getArea 메서드를 중복생성하고 모든 인스턴스가 중복 소유한 상태
- 상속에 의한 메서드 공유
//생성자 함수
function Circle (radius) {
this.radius = radius;
}
//Circle 생성자 함수가 생성한 모든 인스턴스가 getArea 메서드를
//공유해서 사용할 수 있도록 프로토타입에 추가
//프로토타입은 Circle 생성자 함수의 prototype 프로퍼티에 바인딩됨
Circle.prototype.getArea = function () {
return Math.PI * this.radius **2
};
const circle1 = new Circle(1);
const circle2 = new Circle(2);
//Circle 생성자 함수가 생성한 모든 인스턴스는 부모 객체의 역할을 하는
//프로토타입 Circle.prototype으로부터 getArea 메서드를 상속받음
//즉, Circle 생성자 함수가 생성하는 모든 인스턴스느 하나의 getArea 메서드를 공유함
console.log(circle1.getArea === circle2.getArea); //true
console.log(circle1.getArea()); //3.141592653589793
console.log(circle2.getArea()); //12.566370614359172
- Circle 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입. 즉 상위 객체 역할을 하는 Circle.prototype의 모든 프로퍼티와 메서드를 상속받음
- getArea 메서드는 단 하나만 생성되어 프로토타입인 Circle.prototype의 메서드로 할당되어 있음
19.3 프로토타입 객체
프로토타입
- 객체 간 상속(inheritance)를 구현하기 위해 사용
- 어떤 객체의 상위(부모) 객체의 역할을 하는 객체
- 다른 객체에 공유 프로퍼티(메서드 포함) 제공
- 모든 객체는 [[Prototype]] 이라는 내부 슬롯을 가지고, 이 내부 슬롯의 값은 프로토타입의 참조
- 객체가 생성될 떄 객체 생성 방식에 따라 프로토타입이 결정되고 [[Prototype]]에 저장
- 모든 객체는 하나의 프로토타입을 가짐
- 모든 프로토타입은 생성자 함수와 연결되어 있음
- 프로토타입은 자신의 constructor 프로퍼티를 통해 생성자함수에 접근 가능
- 생성자 함수는 자신의 prototype 프로퍼티를 통해 프로토타입에 접근 가능
19.3.1 __proto__ 접근자 프로퍼티
- 모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입, 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근 가능
1) __proto__는 접근자 프로퍼티다
- __proto__ 접근자 프로퍼티를 통해 프로토타입에 접근하면 내부적으로 __proto__접근자 프로퍼티의 getter 함수인 [[Get]]이 호출
- __proto__ 접근자 프로퍼티를 통해 새로운 프로토타입을 할당하면 __proto__ 접근자 프로퍼티의 setter 함수인 [[Set]]이 호출
const obj = {};
const parent = {x:1};
//getter 함수인 get__proto__가 호출되어 obj 객체의 프로토타입을 취득
obj.__proto__;
//setter 함수의 set__proto__가 호출되어 obj 객체의 프로토타입을 교체
obj.__proto__ = parent;
console.log(obj.x); //1
2) __proto__ 접근자 프로퍼티는 상속을 통해 사용된다.
- 모든 객체는 상속을 통해 Object.prototype.__proto__ 접근자 프로퍼티를 사용할 수 있다.
const person = {name:'Lee'};
//person 객체는 __proto__ 프로퍼티를 소유하지 않는다
console.log(person.hasOwnProperty('__protp__')); //false
//__proto__ 프로퍼티는 모든 객체의 프로토타입 객체인 Object.prototype의 접근자 프로퍼티다
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
//{get: [Function: get __proto__],set: [Function: set __proto__],enumerable: false,configurable: true}
//모든 객체는 Object.prototype의 접근자 프로퍼티 __proto__를 상속받아 사용할 수 있다
console.log({}.__proto__ === Object.prototype); //true
3) __proto__ 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유
- 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지 하기 위해
- 프로토타입 체인은 단방향 링크드 리스트로 구현되어야함
- 순환 참조하는 프로토타입 체인이 만들어지면 프로토타입 체인 종점이 존재하지 않기 때문에 프로토타입 체인에서
프로퍼티를 검색할 때 무한 루프에 빠짐
4) __proto__ 접근자 프로퍼티를 코드 내에서 직접 사용하는 것은 권장하지 않는다.
Object.getPrototypeof 메서드
- __proto__ 접근자 프로퍼티 대신 프로토타입의 참조를 취득하고 싶을 때
Object.setPrototypeof 메서드
- __proto__ 접근자 프로퍼티 대신 프로토타입을 교체하고 싶을 때
19.3.2 함수 객체의 prototype 프로퍼티
- 함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킴
//함수 객체는 prototype 프로퍼티를 소유한다
(function () {}).hasOwnProperty('prototype'); //true
//일반 객체는 prototype 프로퍼티를 소유하지 않는다
({}).hasOwnProperty('prototype'); //false
- 모든 객체가 가지고 있는 __proto__ 접근자 프로퍼티와 함수 객체만이 가지고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가리킴
- 하지만 이들 프로퍼티를 사용하는 주체가 다름
구분 | 소유 | 값 | 사용 주체 | 사용 목적 |
__proto__ 접근자 프로퍼티 |
모든 객체 | 프로토타입의 참조 | 모든 객체 | 객체가 자신의 프로토타입에 접근 또는 교체하기 위해 사용 |
prototype 프로퍼티 | constructor | 프로토타입의 참조 | 생성자 함수 | 생성자 함수가 자신이 생성할 객체(인스턴스)의 프로토타입을 할당하기 위해 사용 |
19.3.3 프로토타입의 constructor 프로퍼티와 생성자 함수
- 모든 프로토타입은 constructor 프로퍼티를 가짐
- constructor 프로퍼티는 prototype 프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킴
//생성자 함수
function Person(name) {
this.name = name;
}
const me = new Person('Lee');
//me 객체의 생성자 함수는 Person이다
console.log(me.constructor === Person); //true
- Person 생성자 함수는 me 객체 생성
- me 객체의 프로토타입인 Person.prototype에는 constructor 프로퍼티가 있음
- me 객체는 프로토타입인 Person.prototype의 constructor 프로퍼티를 상속받아 사용 가능
19.4 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입
- 리터럴 표기법에 의해 생성된 객체도 프로토타입 존재
//obj 객체는 Object 생성자 함수로 생성한 객체가 아니라 객체 리터럴로 생성
const obj = {};
//하지만 obj 객체의 생성자 함수는 Object 생성자 함수이다
console.log(obj.constructor === Object); //true
- 객체 리터럴이 평가될 때는 추상 연산 OrdinaryObjectCreate를 호출하여 빈객체를 생성하고 프로퍼티를 추가하도록 정의
- 객체 리터럴에 의해 생성된 객체는 Object 생성자 함수가 생성한 객체가 아님
추상 연산(abstract operation)
- ECMAScript 사양에서 내부 동작의 구현 알고리즘을 표현한 것
19.5 프로토타입의 생성 시점
- 모든 객체는 생성자 함수와 연결되어 있음
- 프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성
사용자 정의 생성 함수
- 사용자가 직접 정의
빌트인 생성 함수
- 자바스크립트가 기본 제공
19.5.1 사용자 정의 생성자 함수와 프로토타입 생성 시점
- constructor (생성자 함수로서 호출 할 수 있는 함수)는 함수 정의가 평가되어 함수 객체를 생성하는 시점에
프로토타입도 더불어 생성
- non-constructor은 프로토 타입이 생성되지 않음
//함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성
console.log(Person.prototype); //{constructor:f}
//생성자 함수
function Person (name) {
this.name = name;
}
- 생성된 프로토타입은 Person 생성자 함수의 prototype 프로퍼티에 바인딩됨
- 생성된 프로토타입의 프로토타입은 Object.prototype이다
19.5.2 빌트인 생성자 함수와 프로토타입 생성 시점
빌트인 생성자 함수
- Object, String, Number, Function, Array, RegExp, Date, Promise
- 모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성
- 빌트인 생성자 함수도 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성
- 객체가 생성되기 이전에 생성자 함수와 프로토타입은 이미 객체화되어 존재
- 이후 생성자함수 또는 리터럴 표기법으로 객체를 생성하면 프로토타입은 생성된 객체의 [[Prototype]] 내부 슬롯에 할당
- 생성된 객체는 프로토타입을 상속받음
'JavaScript' 카테고리의 다른 글
[Deep dive] 19장 프로토타입 (3) (0) | 2023.08.11 |
---|---|
[Deep dive] 19장 프로토타입(2) (0) | 2023.08.10 |
[Deep dive] 18장 함수와 일급객체 (0) | 2023.08.10 |
[Deep dive] 17장 생성자 함수에 의한 객체 생성 (0) | 2023.08.10 |
[Deep dive] 16장 프로퍼티 어트리뷰트 (0) | 2023.08.09 |