일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 모던 자바스크립트 TIL
- frontend roadmap study
- 프로그래머스 K_Digital Training
- 모던 자바스크립트 Deep Dive TIL
- react 프로젝트 리팩토링
- 백준 js
- KDT 프로그래머스 데브코스 프론트엔드
- 리팩토링 회고
- Vue3 Router
- 개발자 특강
- KDT 프로그래머스
- 프로그래머스 데브코스 프론트엔드 TIL
- useEffect return
- useRef 지역 변수
- 모던 javascript Deep Dive
- 인프런 자바스크립트 알고리즘 문제풀이
- 머쓱이
- 모던 자바스크립트 Deep Dive
- K_Digital Training
- 프로그래머스 데브코스 프론트엔드
- 투포인터알고리즘 js
- react customHook 예시
- 프로그래머스 K_Digital Training 프론트엔드
- TypeScript 문법 소개
- 우테캠 회고록
- Vue3
- 백준 node.js
- 모던 자바스크립트 딥다이브
- 프로그래머스 데브코스
- Frontend Roadmap
- Today
- Total
프론트엔드 개발자의 기록 공간
[JavaScript DeepDive] 19장_프로토타입 본문
자바스크립트는 명령형, 함수형, 프로토타입 기반 객체지향 프로그래밍을 지원하는
멀티 패러다임 프로그래밍 언어이다.
자바스크립트는 객체 기반의 프로그래밍 언어이며 자바스크립트를 이루고 있는 거의 "모든 것"이 객체다.
원시타입을 제외한 나머지 값들(함수, 배열, 정규 표현식 등)은 모두 객체이다.
✍ 객체지향 프로그래밍
객체지향 프로그래밍은 객체의 상태를 나타내는 데이터와 상태 데이터를 조작할 수 있는 동작을
하나의 논리적인 단위로 묶어 생각한다. 따라서 객체는 상태 데이터와 동작을 하나의 논리적인 단위로 묶은 복합적인 자료구조라고 할 수 있다.
이때 객체의 상태 데이터를 프로퍼티, 동작을 메서드라 부른다.
const circle = {
radius: 5, // 상태 데이터를 나타내는 프로퍼티
// 동작을 나타내는 메서드
getDiameter() {
return 2 * this.radius;
}
}
✍ 상속과 프로토타입
JavaScript는 흔히 프로토타입 기반 언어(prototype-based language)라 불립니다. 모든 객체들이 메서드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미입니다. 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메서드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메서드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.
정확히 말하자면 상속되는 속성과 메서드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있습니다.
JavaScript에서는 객체 인스턴스와 프로토타입 간에 연결(많은 브라우저들이 생성자의 prototype 속성에서 파생된 __proto__ 속성으로 객체 인스턴스에 구현하고 있습니다.)이 구성되며 이 연결을 따라 프로토타입 체인을 타고 올라가며 속성과 메서드를 탐색합니다.
자바스크립트는 프로토타입을 기반으로 상속을 구현한다.
// 생성자 함수
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의 메서드로 할당되어 있다.
따라서 Circle 생성자 함수가 생성하는 모든 인스턴스는 getAtea 메서드를 상속받아 사용할 수 있다.
즉 상속은 코드의 재사용이란 관점에서 매우 유용하다.
✍ 프로토타입 객체
위에도 언급했듯이 프로토타입 객체란 객체지향 프로그래밍의 근간을 이루는 객체 간 상속을 구현하기 위해 사용된다.
모든 객체는 [[Prototype]]이라는 내부 슬롯을 가지며, 이 내부 슬롯의 값은 프로토타입의 참조(null인 경우도 있다)다.
모든 객체는 하나의 프로토타입을 갖는다. 그리고 모든 프로토타입은 생성자 함수와 연결되어 있다.
즉, 객체와 프로토타입과 생성자 함수는 다음 그림과 같이 서로 연결되어 있다.
✍ 함수 객체의 prototype 프로퍼티
함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.
// 함수 객체는 prototype 프로퍼티를 소유한다.
(function () {}).hasOwnProperty('prototype'); // -> true
// 일반 객체는 prototype 프로퍼티를 소유하지 않는다.
({}).hasOwnProperty('prototype'); // -> false
prototype프로퍼티는 생성자 함수가 생성할 객체(인스턴스)의 프로토타입을 가리킨다.
따라서 생성자 함수로 호출할 수 없는 함수, 즉 non-constructor인 화살표함수, ES6 메서드 축약 표현으로 정의한 메서드는 prototype프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.
모든 객체가 가지고 있는(엄밀히 말하면 Object.prototype으로부터 상속받은) __proto__ 접근자 프로퍼티와 함수 객체만이 가지고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가리킨다.
하지만 이들 프로퍼티를 사용하는 주체가 다르다.
구분 | 소유 | 값 | 사용 주체 | 사용 목적 |
__proto__ 접근자 프로퍼티 |
모든 객체 | 프로토타입의 참조 | 모든 객체 | 객체가 자신의 프로토타입에 접근 또는 교체하기 위해 사용 |
prototype 프로퍼티 |
constructor | 프로토타입의 참조 | 생성자 함수 | 생성자 함수가 자신이 생성할 객체(인스턴스)의 프로토타입을 할당하기 위해 사용 |
✍ 사용자 정의 생성자 함수와 프로토타입 생성 시점
"constructor 와 non-constructor의 구문"에서 내부 메서드 [[Constructor]]를 갖는 함수 객체,
즉 화살표 함수나 ES6의 메서드 축약 표현으로 정의하지 않고 일반함수(함수 선언문, 함수 표현식)로 정의한 함수 객체는 new 연산자와 함께 생성자 함수로서 호출할 수 있다.
생성자 함수로서 호출할 수 있는 함수, 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
// 호이스팅으로 함수 객체가 선언된다.
// 함수 정의(constructor)가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.
console.log(Person.prototype); // {constructor: ƒ}
// 생성자 함수
function Person(name) {
this.name = name;
}
생성자 함수로서 호출할 수 없는 함수, 즉 non-constructor는 프로토타입이 생성되지 않는다. (객체도 프로토 타입이 없다.)
// 화살표 함수는 non-constructor다.
const Person = name => {
this.name = name;
};
const Test = {};
// non-constructor는 프로토타입이 생성되지 않는다.
console.log(Person.prototype); // undefined
console.log(Test) // undefined
✍ 프로토타입 체인
function Person(name) {
this.name = name;
}
// 프로토타입 메서드
Person.prototype.sayHello = function () {
console.log(`Hi! My name is ${this.name}`);
};
const me = new Person('Lee');
// hasOwnProperty는 Object.prototype의 메서드다.
console.log(me.hasOwnProperty('name')); // true
자바스크립트는 객체의 프로퍼티(메서드 포함)에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인이라 한다. 프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다.
프로토타입 체인의 최상위에 위차하는 객체는 언제나 Object.prototype이다.
따라서 모든 객체는 Object.prototype을 상속 받는다. Object.prototype을 프로토타입 체인의 종점이라 한다. Object.prototype의 프로토타입, 즉 [[Prototype]] 내부 슬롯의 값은 null이다.
그 외에도 프로퍼티에 대한 다양한 목차와 설명이 있지만 여기까지만 축약해서 정리
👨💻 프로퍼티... 너무 내용도 방대하고 비슷한 내용에 동작원리까지 아주 복잡한 파트였다.
"자바스크립트의 모든 객체는 프로토타입(prototype)이라는 객체를 가지고 있다."
"non-constructor은 prototype이 생성되지 않는다".
이 두 문장이 엄청 헷갈렸었다. "아니 모든 객체는 프로토 타입이라는 객체는 있다면서 화살표 함수나 ES6의 메서드 축약 표현으로 작성한 함수, 즉 non-constructor은 왜 생성되지 않아? 그럼 둘 중에 하나는 틀린 표현인가?" 라고 생각했다.
하지만 계속 다시 읽고, 다른 블로그에서 찾아본 결과
"자바스크립트의 모든 객체는 프로토타입(prototype)이라는 객체를 가지고 있다." 이 말은
모든 객체들이 메서드와 속성들을 상속받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미였다. 즉 모든 객체들은 최상위 Object.prototype를 상속받기 위한 프로토타입 객체를 가진다.
"non-constructor은 prototype이 생성되지 않는다". 이 말은
non-constructor으로 생성된 함수 객체는 상속을 할 수 없다는 말이었다.
즉
일반 함수(함수 선언문, 함수 표현식)로 정의된 객체는 new 연산자와 함께 생성자 함수로서 호출할 수 있다는 의미이고 이것은 또 다른 일반 함수가 상속을 받을 수 있다는 말이었다.!
자바에서 생각하면 extends 키워드를 이용해서 상속을 이용하지만, 자바스크립트에서는 new 생성자와 프로토타입을 통해 상속을 표현한다.
(class키워드는 추후 포스팅 (JavaScript **Class**는 ECMAScript 6을 통해 소개되었습니다. ES6의 Class는 기존 prototype 기반의 상속을 보다 명료하게 사용할 수 있도록 문법을 제공합니다. 이를 Syntatic Sugar라고 부르기도 합니다.) )
(100% 이해한 것이 아니므로 잘못된 설명일 수도 있다.)
'모던 자바스크립트 Deep Dive' 카테고리의 다른 글
[JavaScript DeepDive] 22장_this (0) | 2022.02.18 |
---|---|
[JavaScript DeepDive] 20~21장 (0) | 2022.02.17 |
[JavaScript DeepDive] 18장_함수와 일급 객체 (0) | 2022.02.14 |
[JavaScript DeepDive] 17장_생성자 함수에 의한 객체 생성 (2) | 2022.02.14 |
[JavaScript DeepDive] 16장_프러퍼티 어트리뷰트 (0) | 2022.02.13 |