프로토타입(prototype)의 모든 것 - 2/3편 : 은행의 서비스 저장소


안녕하세요 이녀석입니다.😎

 

자바스크립트의 공부방법으로 공식문서인 MDN이나 W3Schools, 도서, 강의가 있을 겁니다.

저도 마찬가지였고 지금도 현재 진행형이죠.

 

공부하면서 느낀건데 MDN을 보면 번역본이다 보니 이해하기 조금 난해한 부분이 분명 있었고,

저뿐만 아닌 다른 분들도 그런 부분이 있으셨을 거예요.

 

그래서 제가 이해한 것들을 쉽게 기록을 해보려 합니다.

쉽게 하려다 보니 공식 문서나 여러 강의와 다른 부분이 있을 테지만 제 글을 읽고

분명 도움이 되리라 하는 마음에 포스팅을 작성해 나가도록 하겠습니다.

혹여 부족한 부분과 다른 좋은 내용을 언제든 알려주시면 감사히 배울 테니 언제든 알려주세요.

 

감사합니다.😎

 


 

<프로토타입(prototype)의 모든 것>은 총 3편과 번외편으로 나눠서 포스팅합니다.

  • 프로토타입(prototype)을 느껴라
  • 은행의 서비스 저장소
  • 앱(App)으로 가능해진 은행 업무
  • (번외) MDN도 다 이유가 있었구나!

은행의 서비스 저장소

 
자바스크립트에서 객체가 공통 메서드와 프로퍼티를 사용할 수 있는 이유는 프로토타입 체인을 이용했기 때문입니다.

작가 vectorjuice 출처 Freepik

 

 

은행은 고객들을 위해 다양한 서비스가 있습니다.

예금, 적금, 대출 등 말이죠.

 

이런 서비스 또는 상품들은 당연히 미리 만들어 놓겠죠?

 

고객들은 미리 만들어져 있는 상품들을 직원을 통해 자유롭게 가입하거나 이용을 하게 됩니다.

 

지난 포스팅 마지막에 client.getCreditScore()가 동작했던 이유가 바로 이것과 같습니다.

 

우리은행(WooriBank 생성자)이 미리 서비스(getCreditScore 함수)를 만들었기 때문에 고객(client 상수)은 은행에 가입만 한다면 여러 서비스와 상품들을 직원을 통해 마음대로 이용할 수 있게 되는 것이고 여러 서비스 중에 하나인 고객의 신용점수(getCreditScore 함수)를 확인할 수 있던 것이죠.

 

그렇다면 이제, 숨겨져 있던 코드를 확인하러 가볼까요?🚀

 

 


잠깐!!✋

숨겨져 있는 코드를 보기 전에 먼저 알고 가셔야 할 게 있습니다😉

여러분들! 혹시 함수가 객체라는 사실을 알고 계신가요?

알고 계셨다면 숨겨져 있던 코드를 바로 보시면 되고 모르셨다면 잠시 이것을 보고 가세요!!

(숨겨져 있던 코드 바로가기)

 

function 이녀석() {}; // 빈 함수를 정의

이녀석.성적 = {
  국어: 'A',
  영어: 'B',
  수학: 'C',
}

console.log(이녀석.성적); // {국어: 'A', 영어: 'B', 수학: 'C'}

console.log(typeof 이녀석); // 'function'

 

위 코드를 보면 빈 함수인 '이녀석' 함수가 점(.)을 사용해서 '성적'이라는 객체를 프로퍼티로 추가하고 콘솔로 확인해보니 정상 동작하는 것을 알 수 있습니다.

 

어떠신가요? 함수도 객체가 맞죠? 객체 맞습니다😀

 

그렇지만 'typeof 연산자'로 객체인지 아닌지 확인해보니 'object'가 아니라 'function'이라네요....?

함수인지 객체인지 헷갈리시겠지만 이건 자바스크립트가 만들어질 때의 실수가 아닌가 싶습니다😅

 

결론은 '함수는 함수면서 객체다'라고 생각하시면 될 것 같아요.

 

그럼 이 내용을 기억하시고 드.디.어 숨겨져 있던 코드를 보겠습니다🚀

 

function WooriBank(name, age, product) {
    this.name = name;
    this.age = age;
    this.product = product;
    this.getMoney = function(){
        console.log(`[${this.product}]이 만기가 됐으므로 만기수령금을 수령해주세요^^`);
    }
}

WooriBank.prototype.getCreditScore = function() { /*** 숨겨져 있던 코드 (1) ***/
    console.log(`${this.name}고객님의 신용점수는 100점입니다.`)
}

const client = new WooriBank('이녀석', '31', '이자가 매우 쎈 적금');
  • /*** 숨겨져 있던 코드 (1) ***/ : WooriBank.prototype에 getCreditScore 메서드를 추가

/*** 숨겨져 있던 코드 (1) ***/ 를 보시면 WooriBank라는 생성자 함수에 'prototype'이라는 프로퍼티가 있습니다.

함수도 객체인 것을 아시죠?

 

제가 프로퍼티를 추가한 적이 없는데 어디서 생겨난 것일까요?

또 제가 여러분들 몰래 숨긴 코드가 있는 걸까요?

 

자바스크립트에 의해 자동으로 추가된 Parent함수의 프로퍼티들

당연히 아닙니다.

자바스크립트에서는 함수를 정의하면 자동으로 추가가 되는 프로퍼티가 있는데, 위 콘솔 이미지에 있는 프로퍼티들이 자동으로 추가가 됩니다.

 

그리고 위 콘솔 이미지를 보시면 prototype이 있습니다.

이 prototype이라는 프로퍼티를 /*** 숨겨져 있던 코드 (1) ***/ 에서 WooriBank.prototype으로 사용한 것이죠.

 

그리고 이 prototype 프로퍼티가 이번 포스팅의 주제인 prototype을 말하는 것이며,

이것을 발견하기 위해 저희가 1편부터 지금까지 달려온 것입니다!!🏃‍♂️🏃‍♀️

 

 

prototype 프로퍼티는 위에 보시는 바와 같이 객체입니다.

그래서 여러 곳에서 'prototype 객체' 또는 'prototype object'라고 불리는 것이죠.

 

작가 pch.vector 출처 Freepik

 

 

이번 포스팅 첫 부분에서 고객들은 은행이 미리 만들어 놓은 서비스와 상품을 직원을 통해 이용할 수 있다고 한 것을 기억하시나요?

 

prototype 프로퍼티가 바로 은행의 서비스와 상품이 저장되어 있는 공간입니다.

WooriBank.prototype 이라는 공간을 통해  getCreditScore함수를 실행하여 고객의 신용점수를 알 수 있던 것이죠.

 

근데 WooriBank생성자 내부에 낭비가 되는 코드가 있습니다.

바로 getMoney함수입니다.

 

const client1 = new WooriBank('이녀석', '31', '이자가 매우 쎈 적금');
const client2 = new WooriBank('그녀석', '32', '보통의 예금');
const client3 = new WooriBank('저녀석', '33', '아주 좋은 예금');

console.log(client1);
console.log(client2);
console.log(client3);

 

왜냐하면 고객들이 생길 때마다 getMoney함수가 생기기 때문입니다.

 

만기수령금(getMoney함수)도 결국에는 은행에서 제공하는 서비스입니다.

그래서 은행의 서비스와 상품이 저장되어있는 공간인 WooriBank.prototype에 한 번만 저장하여 사용하는게 더 좋습니다.

 

새롭게 코드를 보시죠.

 

function WooriBank(name, age, product) {
    this.name = name;
    this.age = age;
    this.product = product;
}

WooriBank.prototype.getCreditScore = function() {
    console.log(`${this.name}고객님의 신용점수는 100점입니다.`)
}

WooriBank.prototype.getMoney = function(){ // getMoney를 prototype의 메서드로 추가
    console.log(`${this.name}님, [${this.product}]이 만기가 됐으므로 만기수령금을 수령해주세요^^`);
}

const client1 = new WooriBank('이녀석', '31', '이자가 매우 쎈 적금');
const client2 = new WooriBank('그녀석', '32', '보통의 예금');
const client3 = new WooriBank('저녀석', '33', '아주 좋은 예금');

console.log(client1);
console.log(client2);
console.log(client3);

client1.getMoney();
client2.getMoney();
client3.getMoney();

 

고객마다 getMoney함수가 없어도 잘 동작하는 것을 볼 수 있습니다.

 

이렇게 잘 동작하는 이유는 자바스크립트의 '프로토타입 체인(prototype chain)' 이라는 특성 때문입니다.

말 그대로 'prototype 프로퍼티'가 연결되어 있다는 뜻입니다.

 

console.log(client1);

 

콘솔로 client1을 살펴보면 [[Prototype]]이라는 은닉속성이 있습니다.

이것도 자바스크립트에서 자동으로 추가가 되는 속성입니다.

이 속성은 객체라면 반드시 무조건 가지고 있습니다.

(예전에는 __proto__로 표시 되었지만 이제는 [[Prototype]]으로 표시 됩니다. 자세히 알고 싶으면 'js 내부슬롯', 'js 인터널 슬롯'을 검색해보세요^^)

 

[[Prototype]]을 살펴보니 getCreditScore함수, getMoney함수가 있습니다.

이 함수들이 왜 여기에 있는 것 일까요?

분명 이 함수들은 WooriBank.prototype에서 정의한 함수인데 말이죠.

 

console.dir(WooriBank);

 

그것은 바로,

[[Prototype]]이라는 은닉속성이 WooriBank.prototype(생성자.prototype)을 참조하기 때문입니다.

 

WooriBank.prototype(생성자.prototype)을 참조하기 때문에 '프로토타입 체인(prototype chain)'이라는 특성이 적용되어 client1(객체)에서 직접 정의한 적 없는 프로퍼티, 메서드를 사용할 수 있게 되는 것이죠.

 

즉, 객체는 직접 정의하지 않았더라도 [[Prototype]]에 있는 모든 프로퍼티, 메서드를 사용할 수 있습니다.

예시를 간단히 보고 마무리 하겠습니다.

 

const fruits = ['사과', '바나나'];

fruits.push('오렌지');

console.log(fruits); // ['사과', '바나나', '오렌지]

 

fruits는 배열이고, push는 메서드입니다.

fruits에서 push를 정의하지 않았는데 '오렌지'가 왜 추가가 되었을까요?

 

console.log(fruits);

 

지금까지 저희가 이유도 모른채 값을 추가하기 위해 사용했던 push는 배열의 [[Prototype]]은닉속성이 참조하는 객체에 push가 있었기 때문입니다.

 

다음 시간에는 생성자의 상속(확장)에 대해서 알아보겠습니다.