Front-end/JavaScript

[JS] 프로토타입

파리외 개발자 2022. 8. 17. 00:18
현재는 클래스 또한 문법적으로 지원을 하지만
원래 JS는 Prototype을 기반으로 확장, 재사용성을 가지는 언어이다.
oop, 상속, 확장, 오버라이딩.., 을
JS는 어떤 방식으로 풀어냈는지 알아보자

첫 번째 이야기 : 과일의 속성 (상속, 오버라이딩)

여기 과일을(이름은 apple인) 정의했다.

fruit.name은?? apple이다.

사과의 색은 빨간색이기에 fruit에 color속성을 red로 추가해주었다.

fruit.color는?? red다.

이쯤에서 fruit의 속성은 무엇이 있는지 궁금해서 hasOwnProperty메서드를 사용해 알아보았다.

color속성은 true로 존재한다고 하고

shape속성은 false로 없다고 한다. 아직 만들지 않았으니깐

잠깐...그런데 hasOwnProperty라는 메서드를 fruit에 정의했던가?

이쯤에서 fruit의 정체를 알아봐야겠다.

fruit의 color는 red, name은 apple로써 정의한대로다.

그런데 그 아래에 흐린글씨로 prototype:Object라고 되어있다.

그리고 그 안엔 아까 정의하지 않아도 사용이 되었던 hasOwnProperty가 존재하는 것을 볼 수 있다.

여기서 알 수 있는것이 몇 가지 있다.

  • fruit는 정의한 두 개의 속성말고 'Prototype'이란 속성을 하나 더 숨기고 있다.
  • 이 속성은 fruit를 Object, 즉 객체라고 말하고 있다.
  • fruit의 prototype(원형)은 Object(객체)이다. 즉 fruit는 Object에서 파생되었다.
  • 그렇기 때문에 fruit는 Object의 메서드인 hasOwnProperty를 사용할 수 있었다.
JS의 개체는 원형인 prototype을 통해 '상속' 받아 proto객체의 메서드를 사용할 수 있다.

🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇🍇

보라색 글씨를 보다보니 포도가 먹고싶다.

이번엔 fruit2를 grape, purple로 만들고 hasOwnProperty를 정의해봤다.

정의하기 전의 상속받은 hasOwnProperty는 속성의 존재유무를 boolen형태로 리턴해주었다.

하지만 포도의 hasOwnProperty는 어떻게 작동할까? Is it work?

상속받은 메서드가 아닌 새롭게 포도에서 재정의한 메서드가 실행되는 것을 볼 수 있다.

JS의 상속받은 개체는 상속받은 메서드를 '오버라이딩'하여 재정의해서 사용할 수 있다.

 

두 번째 이야기 : 요일별 연차 (prototype, constructor속성)

day 함수를 정의 후 mon과 fri라는 두 인스턴스 객체를 생성했다.

앞서 객체에는 proto라는 속성이 있고 해당 프로토타입의 상속을 받는다고 보았었다.

그럼 day로 만들어진 두 객체는 어떨까?

두 객체 모두 Object의 원형을 가지는 day라고 나온다.

즉 mon과 fri는 day라는 오브젝트 객체이며

두 객체의 proto속성은 모두 day 함수의 prototype객체를 가르키는 것을 알 수 있다.

또한 day함수의 프로토타입 객체는 제일 최상위 객체인 Object 그 자체를 상속받고 있다.

  • mon -> day -> Object
  • fri -> day -> Object

그런데 여기서 day의 프로토타입 객체는 constructor라는 속성을 또 가지고 있는 것을

볼 수 있다. 생성자라고도 불리는 이 속성은 무엇일까?

day의 프로토타입객체에 연차라는 메서드를 정의했다. (day자체에 생성한 것이 아님)

그리고 두 인스턴스 객체인 mon과 fri는 day를 상속받았으므로

day의 yuncha메서드를 사용할 수 있다.

인자 whatday에 해당 인스턴스의 이름을 넣고 실행시켜보니

this.constructor.name이 day라는 값을 가지는 걸 실행결과를 통해 알 수 있다.

여기서 this가 day를 가르키는 것은 알 수 있는데 (함수에서의 this는 자기자신을 가르킴)

constructor라는 속성을 정의한 적이 없는데 대체 어디서 나온 것일까?

앞의 day객체의 constructor속성을 열어보니

여러 속성들이 존재하고 name속성이 day값을 가짐을 알 수 있다.

또 name속성 아래에 prototype속성이 또 존재하는 것을 볼 수 있다.

열어보면 또 constructor가 보이고 그걸 열면 또 prototype이 보이고

무한반복을 보니 엘리베이터의 거울을 보는 듯 하다.

이를 통해 눈치챌 수 있겠지만 proto속성과 constructor속성은 서로를 가르키고 있음을 알 수 있다.

  • day가 생성되어 실행될 때 같은 이름의 day prototype 또한 같이 생성됨
  • day의 prototype속성day prototype객체를 가르키게 됨
  • day prototype객체는 constructor속성을 가지고 이 속성은 day를 가르키게 됨
함수는 같은 이름의 prototype객체를 가지며 이 둘은 각각 prototype속성consturctor속성으로 서로를 가르킨다.

이번엔 인스턴스 객체 그 자체에 메서드를 추가해봤다.

따로 정의한 메서드가 없는 mon은 그대로 부모 메서드를 상속받아 월요일에 연차를 쓰겠다고 하고

fri객체는 새로 정의한 메서드를 실행시키게 된다.

이어서 mon에도 feel이라는 속성을 추가해줬다.

fri에는 상속받을 feel속성도 없으니 undefined가 출력된다.

그럼 여기서 각 인스턴스 객체는 어떻게 바뀌었을까?

각각 prototype속성은 day객체를 가지고 day객체또한 변화한 것은 없지만

그 속성위에 feel속성과 yuncha메서드를 고유하게 가지고 있는 것을 볼 수 있다.

 

세 번째 이야기 : 더하기 (객체마다 생성되는 메서드)

위에서 인스턴스 자체에 생성한 메서드는 속성처럼 고유하게 가지는 것을 볼 수 있었다.

그런데 메서드는 굳이 고유하게 가질 필요가 없는 경우가 대다수이다.

이를 위해 하나의 예를 보겠다.

Add라는 함수형 클래스는 a와 b라는 두 속성 외에 plus라는 더하기 메서드를 가진다.

멤버변수 2개에 멤버함수1개의 총 3개의 멤버를 가지는 클래스라 볼 수 있다.

그리고 아래에 add1~3까지 3개의 인스턴스에 각각 다른 인자를 전달해 결과를 실행했다.

Add2클래스는 똑같이 멤버변수 2개를 가지지만

plus메서드가 prototype객체에 생성되어 실행된다.

마찬가지로 세개의 인스턴스객체를 생성해 결과를 출력했다.

이 두가지 방식은 무슨 차이를 가질까?

콘솔 창을 자세히 본다면 그 차이를 볼 수 있다.

결과는 동일하게 나오지만 위의 세개의 인스턴스 객체는 모두 plus메서드를 가지고 있다.

반면 아래 세개의 객체는 변수만을 가지고 실행이 되었다.

  • 생성자 내에서 선언된 함수는 그 함수의 prototype객체의 constructor속성이 가르키는 Add그 자체에 생성됨
  • Add 그 자체에 생성된 함수는 인스턴스 객체가 실행될때마다 매번 생성되서 실행
  • 반면 prototype객체에서 선언된 함수는 Add의 prototype속성이 가르키는 Add의 prototype객체에 생성됨
  • Add의 prototype객체에 생성된 함수는 인스턴스 객체가 공통으로 사용할 수 있음
공통적으로 사용되는 멤버변수 또는 메서드는 prototype객체에 생성하여 재사용을 하게하여 메모리 손실을 방지한다.

 

'Front-end > JavaScript' 카테고리의 다른 글

JS 동작원리 1편 - 자바스크립트 엔진, V8  (0) 2022.11.01
[JS] new 연산자  (0) 2022.08.20
[JS] this 가 가르키는 것  (0) 2022.08.14
[JS] Symbol  (0) 2022.08.08
[JS] 중복없는 자료구조, Set  (0) 2022.08.07