일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 29 | 30 | 31 |
- CSS
- 국비지원취업
- github
- 알고리즘
- nodejs
- Javascript
- KAKAO
- 컴퓨터과학
- 코테
- 국비지원
- 부트캠프
- 코딩테스트
- 야놀자
- 너비우선탐색
- LinkSnap
- CS
- 백준
- computerscience
- html/css/js
- cpu
- 자바스크립트
- 프론트엔드개발자
- 그리디
- 컴퓨터공학
- BFS
- 패스트캠퍼스
- DFS
- git
- js
- 호이스팅
- Today
- Total
My Boundary As Much As I Experienced
JS) 프로토타입(Prototype) 본문
자료형을 생성하는 2가지 방식
프로토타입을 만들기 전에 예시로 배열을 만드는 데는 2가지 방법을 사용해보자
const fruits = ["Apple", "Banana", "Cherry"];
//배열 리터럴 방식
const fru2 = new Array("Apple", "Banana", "Cherry");
//사실 리터럴로 입력해도 컴퓨터는 생성자 함수 방식으로 생성한다.
하나는 배열 리터럴 방식으로, []을 이용해서 직관적으로 자신이 넣고싶은 데이터들을 넣을 수 있다.
나머지 하나는 생성자 함수를 사용하는 방법이다. new 연산자와 맨 앞글자가 대문자인(파스칼 표기법) 생성자 함수를 사용하는 방식이다.
Array뿐만 아니라, Object도 이와 같이 생성할 수 있다. 생성자 함수(틀)에서 내가 원하는 객체, 배열(결과물)들을 찍어내는 방식이다.
배열 리터럴 방식을 사용해도 컴퓨터는 생성자 함수를 통해 복제한 결과물을 반환하는 것이었다.
const fruits = ["apple", "banana"]
console.log(fruit.length)
console.log(fruit.includes("apple"))
console.log(fruit.forEach(fruit => console.log(fruit)))
// 우리가 알고 있는 Array 자료형일 때 사용할 수 있는 메소드들. 왜 사용할 수 있는지 생각해본 적 있나?
우리가 배열을 생성하면 기본적으로 사용할 수 있는 속성 혹은 메소드들이 있었다. 이 메소드들도 어딘가에 선언되어 있기 때문에 우리가 쓸 수 있는거다. 그곳은 바로! 프로토타입이란 곳이다. 생성자 함수를 만들면 (자바스크립트는 우리가 모르게) 그에 대응하는 프로토타입이라는 객체를 만든다.
이렇듯 프로토타입에 선언해서 모든 인스턴스에서 사용할 수 있는 메소드를 프로토타입 메소드라고 부른다. 그에 반해 인스턴스에선 사용할 수 없고 생성자 함수에서만 사용할 수 있는 메소드도 있는데 이를 정적 메소드라고 부른다. 당장 정적 메소드에 대해 자세하게 다루진 않겠지만, 프로토타입 메소드가 어떻게 선언되어 있는지는 알 필요가 있다.
생성자 함수로 프로토타입 프로퍼티 생성
function Person(first, last, height) {
this.firstName = first
this.lastName = last
this.height = height
}
생성자 함수는 직접 만들어볼수도 있다. 위처럼 Person이란 새로운 생성자 함수를 만들었다고 해보자.
그러면 자바스크립트는 위와 같이 Person이란 생성자 함수와 그에 대응하는 Person의 프로토타입을 만드는 것이다.
프로토타입은 어떻게 보면 유전자라고 볼 수 있다. Person의 프로토타입은 앞으로 Person이 생성될 때 공통적으로 가지고 가야할 유전자 형질을 상속해주는 존재이다.
프로토타입에 접근하여 메소드 생성
Person.prototype.sum = function (){
console.log(`sum ${this.first}`)
}
우리는 prototype에 접근해서 새로운 메소드도 추가할 수 있다.
const kim = new Person("Josee", "Kim", 166)
const hwang = new Person("Minsu", "Hwang", 177)
kim.sum() // sum Josee
hwang.sum() // sum Minsu
앞서 추가한 메소드를 josee와 minsu안에 직접 만들지 않았어도 Person의 프로토타입을 참조하여 메소드를 찾아 실행시킬 수 있게 되는 것이다. 우리가 알던 Array와 Object 모두 prototype에 프로퍼티와 메소드들을 할당하여 기본적으로 제공하던 것이었다.
우리가 kim이란 인스턴스(복사본)을 Person으로부터 생성했을 때, 아래와 같은 일들이 일어난다.
kim이란 인스턴스를 만들어서 우리가 설정한 name, first, ... 같은 정보들 뿐만 아니라 __proto__라는 보지못한 속성도 추가가 된걸 볼 수 있다. __proto__는 이 인스턴스의 원형이 되는 프로토타입을 참조하도록 걸어둔 link라고 보면 된다.
우리가 메소드를 호출할 때 벌어지는 일들
- 호출한 객체에 해당 메소드가 있는지 찾아본다.
- 없다면 __proto__를 타고 prototype에 접근하여 메소드가 있는지 확인한다.
- 또 없다면 __proto__를 타고 상위 prototype에 접근하여 메소드가 있는지 확인한다.
- 계속 없다면 이렇게 쭉 이어가다가 Object의 프로토타입까지 뒤져보고, Object는 프로토타입이 null이기 때문에 여기서 탐색을 멈추고 참조에러가 뜬다.
__proto__란?
모든 객체는 __proto__를 통해 자신이 물려받은 [[Prototype]] 값에 접근할 수 있다.
재해석 : __proto__라는 프로퍼티로 유전자 접근이 가능하다.
하지만 [[Prototype]] 내부 슬롯에는 직접 접근이 불가하다. 이는 프로토타입 체인의 단방향을 지키기 위해서다. 만약 직접 접근가능하다면, 서로가 서로의 프로토타입이 되면서 프로토타입 체인이 무한으로 돈다. 따라서 __proto__ 프로퍼티로만 접근할 수 있다.
자바스크립트는 객체 지향 언어가 아니라 프로토타입 지향 언어였다.
다른 객체 지향 언어처럼 Class가 없지만 Prototype을 통해 원본과 인스턴스 관계를 생성할 수 있었다.(물론 메소드나 속성을 프로토타입에 지정하는 해괴한 문법을 가지고 있지만..)
그러나 ES6에 이르러 다른 자바같은 언어가 가지고 있는 class 문법을 만들었고, 현재는 class를 사용해서 객체들을 관리할 수 있다. (클래스를 문법적으로 구현해놓았지만 사실 prototype 개념을 조작하는 것이다)
참고
'FrontEnd > Javascript(Vanilla)' 카테고리의 다른 글
JS) 비동기와 Promise (0) | 2023.08.01 |
---|---|
콜백함수 (0) | 2023.08.01 |
JS) this란 무엇인가? (0) | 2023.07.21 |
JS) 화살표 함수 (0) | 2023.07.21 |
JS) 호출 스케줄링 (0) | 2023.07.20 |