본문 바로가기
JavaScript

[js] 자바스크립트 DeepDive 19장(0) ~ (5) 요약

by Delants 2023. 3. 21.

* 본 내용은 자바스크립트 DeepDive 내용을 참고하여 정리한 것입니다.

 

19장. 프로토타입 (0) ~ (5)

 

0. 개요

- 자바스크립트는 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.

- 자바스크립트는 객체 기반으로, 원시 타입의 값을 제외한 나머지 값들은 모두 객체이다.

 

그렇다면 객체지향 프로그래밍이란 무엇인가? 이에 대해 알아보도록 하자.

 

 

1. 객체지향 프로그래밍 (p260~261)

 

● 객체지향 프로그래밍이란?

- 여러 개의 독립적 단위, 즉 객체의 집합으로 프로그램을 표현하려는 프로그래밍 패러다임을 뜻함.

- 객체의 상태를 나타내는 데이터와 동작을 하나의 논리적인 단위로 묶어 생각함.

- 속성을 가진 실체를 인식하려는 철학적 사고를 프로그래밍에 접목하는 것.

 

● 용어소개

- 추상화: 다양한 속성 중에서 프로그램에 필요한 속성만 간추려 표현하는 것

- 객체: 속성을 통해 여러 개의 값을 하나의 단위로 구성한 복합적 자료구조

// 19-01. 객체의 정의
const person = {
    name: 'Choi',
    address: 'busan'
};

console.log(person);
{ name: 'Choi', address: 'busan' }

- 객체의 상태를 프로퍼티, 동작을 메서드라고 부름.

 

 

2. 상속과 프로토타입 (p.261~264)

 

● 상속의 개념

- 어떤 객체의 프로퍼티 또는 메서드를 다른 객체가 상속받아 그대로 사용할 수 있는 것

- 자바스크립트는 프로토타입을 기반으로 상속을 구현하여 불필요한 중복을 제거함.

- 중복을 제거하기 위한 방법으로, 기존 코드를 적극적으로 재사용하는 방법이 있음.

- 상속은 코드의 재사용이라는 관점에서 매우 유용함.

 

 

3. 프로토타입 객체 (p.264~272)

 

● 프로토타입 객체란?

- 객체지향 프로그래밍의 근간을 이루는 객체간 상속을 구현하기 위해 사용됨

- 모든 객체는 [[prototype]]이라는 내부 슬롯을 가지며 이 내부 슬롯의 값은 프로토타입의 참조(혹은 null)이다.

- [[prototype]]에 저장되는 프로토타입은 객체 생성 방식에 의해 결정된다. 

- 즉, 객체 생성 시 객체 생성 방식에 따라 프로토타입이 결정되고, [[prototype]]에 저장된다.

- 모든 객체는 하나의 프로토타입을 갖는다. 그리고 모든 프로토타입은 생성자 함수와 연결되어 있다.

 

● __proto__접근자 프로퍼티

- 모든 객체는 __proto__접근자 프로퍼티를 통해 자신의 프로토타입, 즉 [[prototype]]내부 슬롯에 간접적으로 접근가능하다.

 

1) __proto__는 접근자 프로퍼티이다.

- js는 내부 슬롯과 내부 메소드에 직접적으로 접근하거나 호출할 수 있는 방법을 제공하지 않음

- 그래서 간접 접근하는 방법을 사용하는데 이때 사용되는 것이 __proto__프로퍼티이다.

 

2) __proto__ 접근자 프로퍼티는 상속을 통해 사용된다.

- __proto__접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니라, object.prototype의 프로퍼티이다.

- 모든 객체는 상속을 통해 object.prototype.__proto__ 접근자 프로퍼티를 사용할 수 있다.

- object.prototype이란, 프로토타입의 최상위 객체로서, 이 객체의 프로퍼티와 메소드는 모든 객체에 상속된다.

 

3) __proto__ 접근자 프로퍼티를 통해 프로토타입에 접근하는 이유

- 이 이유는, 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서이다.

프로토타입 체인 (19.7절)
- 객체의 메서드나 프로퍼티에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색하는 것을 말한다.
- 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 매카니즘이다.

 

4) __proto__ 접근자 프로퍼티를 코드 내에서 직접 사용하는 것은 권장하지 않는다.

- 모든 객체가 __proto__접근자 프로퍼티를 사용할 수 있는 것은 아니기 때문.

- 직접 상속을 통해 object.prototype을 상속받지 않는 객체를 생성할 수도 있기 때문에 __proto__접근자를 사용할 수 없는 경우가 생길 수 있다.

- __proto__접근자 프로퍼티 대신 프로토타입 참조를 취득하고 싶을 경우, object.getprototypeof메서드를 사용한다.

- __proto__접근자 프로퍼티 대신 프로토타입 교체하고 싶을 경우 object.setprototypeof메서드를 사용한다.

 

● 함수 객체의 prototype 프로퍼티

- 함수 객체만이 소유하는 prototype프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.

(function () {}).hasOwnProperty('prototype'); // true

({}).hasOwnProperty('prototype'); // false

- non-constructor인 화살표 함수와 es6메소드 축약 표현으로 정의한 메소드는 prototype 프로퍼티를 소유하지 않으며, 프로토타입을 생성하지도 않는다.

- non-constructor란, 객체를 생성자 함수로서 호출할 수 없는 함수로, 화살표와 메서드이다.

- 모든 객체가 가지고 있는 __proto__ 접근자 프로퍼티와 함수 객체만이 가지고 있는 prototype프로퍼티는 결국 동일한 프로퍼티를 가진다. 하지만 이들은 프로퍼티를 사용하는 주체가 다르다.

 

● __proto__접근자 프로퍼티와 prototype프로퍼티의 차이점

구분 소유 사용 주체 사용 목적
__proto__ 
접근자 프로퍼티
모든 객체 프로토타입의 참조 모든 객체 객체가 자신의 프로토타입에 접근 또는 교체하기 위해 사용
prototype 프로퍼티 constructor 프로토타입의 참조 생성자 함수 생성자 함수가 자신이 생성할 객체의 프로토타입을 할당하기 위해 사용

 

● 프로토타입의 constructor프로퍼티와 생성자 함수

- constructor프로퍼티는 prototype프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킨다.

- 모든 프로토타입은 constructor프로퍼티를 갖는다.

 

 

4. 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입 (p.272~276)

 

● 객체 생성 방식에 대한 이해

- 생성자 함수에 의해 생성된 인스턴스는 프로토타입의 constructor프로퍼티에 의해 생성자 함수와 연결된다.

- 먼저 new연산자와 함께 생성자 함수를 호출하여 인스턴스를 생성하지 않는 객체 생성 방식이 있다.

// obj객체를 생성한 생성자 함수는 object이다.
const obj = new Object();
console.log(obj.constructor === Object); //true

// plus 함수객체를 생성한 생성자 함수는 function이다.
const plus = new Function('a', 'b', 'return a+b');
console.log(plus.constructor === Function); // true

// 생성자 함수 만들기
function man(name) {
    this.name = name;
}

// me객체를 통해 생성한 생성자 함수는 man이다.
const me = new man('choi');
console.log(me.constructor === man); // true

 

- 위 방법 말고도 리터럴 표기법에 의한 객체 생성 방식도 존재한다.

- 리터럴 표기법에 의해 생성된 객체도 프로토타입이 존재한다. 하지만constructor프로퍼티가 가리키는 생성자 함수가 반드시 객체를 생성한 생성자 함수라고는 단언할 수 없다.

// 19-16. 리터럴 표기법에 의한 객체 생성

// 객체 리터럴
const obj = {};

// 함수 리터럴
const add = function (a, b) {
    return a+b;
};

// 배열 리터럴
const arr = [1,2,3];

 

● 객체 리터럴의 평가

- 객체 리터럴이 평가될 때에는 추상 연산 OrdinaryObjectCreate를 호출하여 빈 객체를 생성하고 프로퍼티를 추가하도록 정의되어 있다.

- object생성자 함수 호출과 객체 리터럴의 평가는 추상 연산 OrdinaryObjectCreate를 호출하여 빈 객체를 생성한다는 점은 동일

- 하지만 new.target의 확인이나 프로퍼티를 추가하는 처리와 같은 세부 내용은 다르다.

추상 연산
- ECMAScript 사양에서 내부 동작의 구현 알고리즘을 표현한 것.

 

- 함수 객체의 경우, 함수 선언문과 함수 표현식을 평가하여 함수 객체를 생성한 것은  함수 선언문임.

- 하지만 이를 constructor프로퍼티를 통해 확인해 보면 function생성자 함수이다.

function days() {} // 함수 선언문으로 작성된 days함수

console.log(days.constructor === Function); // 하지만 constructor프로퍼티로 확인해보면 TRUE가 나옴으로써 function생성자 함수입니다.

 

- 리터럴 표기법에 의해 생성된 객체도 상속을 위해 프로토타입이 필요하다. 그러므로, 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.

 

 

● 리터럴 표기법에 의해 생성된 객체의 생성자 함수와 프로토타입

리터럴 표기법 생성자 함수 프로토타입
객체 리터럴 object object.prototype
함수 리터럴 Function Function.prototype
배열 리터럴 Array Array.prototype
정규 표현식 리터럴 RegExp RegExp.prototype

 

 

5. 프로토타입의 생성 시점 (p.276~279)

 

● 프로토타입의 생성 시점 개요

- 프로토 타입은 함수의 생성자 함수가 생성되는 시점에 더불어 생성된다.

- 프로토타입과 생성자 함수는 단독으로 존재할 수 없고, 항상 쌍으로 존재하기 때문.

- 생성자 함수는 사용자 정의 생성자 함수와 자바스크립트가 기본 제공하는 빌트인 생성자 함수로 구분됨

 

● 사용자 정의 생성자 함수와 프로토타입 생성 시점

- 생성자 함수로서 호출할 수 있는 함수(constuctor)는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.

- 다만, 생성자 함수로서 호출할 수 없는 함수(non-constructor)는 프로토타입이 생성되지 않는다.

// constructor의 경우, 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 생성됨
console.log(phones.prototype);

function phones(name) {
    this.name = name;
} // {}

// non-constructor의 경우, 프로토타입이 생성되지 않는다.
const phones = name => {
    this.name = name;
};
console.log(phones.prototype); // undefined

- 위에서 생성된 프로토타입은 오직 constructor프로퍼티만을 갖는 객체이다.

- 사용자 정의 생성자 함수에서 생성된 프로토타입의 프로토타입은언제나 object.prototype이다.

 

 

● 빌트인 생성자 함수와 프로토타입 생성 시점

- object, string, number, Function, Array, RegExp, Date, Promise와 같은 빌트인 생성자 함수도 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다.

- 모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성된다.

- 생성자 함수 또는 리터럴 표기법으로 객체를 생성하면, 프로토타입은 생성된 객체의 [[prototype]] 내부 슬롯에 할당되며, 프로토타입을 상속받는다.

 

 

끝.

 

다음 내용: 자바스크립트 DeepDive 19장 (6)~(10) 요약 (p.280~299)

댓글