JS (Java Script)

프로토타입 ( prototype ) 과 __proto__ 차이 명확하다 // 상속 구현하기

GABOJOK 2023. 9. 7. 16:49

prototype

이건 함수에만 생성되며, 상속(inheritance) 기능 구현하는 문법중 하나이다.

생성자 함수(constructor function) 을 이용해서 object를 만들면, prototype 이 자동으로 생긴다. 

자바스크립트의 객체는 숨김 속성을 가진다.

이 숨김 프로퍼티(속성) 에서

다른 객체를 참조하는 경우 참조 대상을 '프로토타입(prototype)'이라 부른다.

쉽게 말하면 부모의 유전자 역할을 해주는 일종의 비밀 공간 같은거!!

 

참고   https://ko.javascript.info/prototype-inheritance

 

프로토타입 상속

 

ko.javascript.info

 

 

그럼 이 prototype이 어떻게 사용될 수 있을까?

  • 부모의 속성들을 상속받을 수 있다.
  • 혹은 반대로 이미 만들어진 생성자 함수(constructor function)에 속성값 처럼 쓰이도록 할 수 있다. 
  • object 자료처럼 prototype 에다 값을 여러개 부여할 수도 있고, 함수도 집어넣을 수 있다. 

 

주의할 점

prototype 에 추가된 데이터들은 추가한 대상이 직접 가지고 있는게 아닌,

추가한 대상의 숨김 프로퍼티가 해당 데이터를 가지고 있다. 

 

 

예시.

function Student(e){
   this.name = e,    
   this.age = 15
   this.sayHi = function(){
      console.log('안녕하세요 ' + this.name + ' 입니다.')
   }
}

let 학생1 = new Student('kim'); 
let 학생2 = new Student('박'); 

학생1.sayHi()  //안녕하세요 kim 입니다.
학생2.sayHi()  //안녕하세요 박 입니다

Student.prototype.gender = '여';  

console.log(학생1.gender)  //여

 

Student 라는 생성자 함수, 즉 constructor function  가 가지고 있는 prototype (숨김속성)에

gender라는 속성 추가 한 상황이다. 

 

 

자바스크립트는 이렇게 해석한다. 

 

1. 학생1 이라는 object 에 gender 라는 키가 있니?  (Y ->  해당 값 출력 ) (N -> 2번 과정 시작)

2. 학생1 의 prototype은  gender 라는 키가 있니? (Y ->  해당 값 출력)  (N -> 3번 과정 시작)

3. 학생1 의 prototype 의 prototype 은  gender 라는 키가 있니? .....

 

 

그 결과 !!!

학생1 이라는 객체는 gender 라는 속성을 가지고 있지 않지만,

그것의 prototype에서 gender 라는 속성을 가지고 있기 때문에 값이 출력되는것.

 

 

 

이런 방식으로 상속이 이루어 진다는걸 알게 되었다. 

그렇지만 prototype은 배열이나 object 에는 존재하지 않는다는 것!!!

(그래서 __proto__ 라는걸 이용한다. )

 

 

 

 

이번엔 배열을 살펴보자.

 

우리가 배열을 만들어 줄 때에,

let arr = [1,2,3,4,5]; 이렇게도 가능하지만,

let arr = new Array (1,2,3,4,5) 이렇게도 가능하다. 

 

보통 첫번째 방법을 많이 사용한다. 

그런데 자바스크립트가 인식하고 만드는 과정은 두번째 방법이다.

 

new 는 생성자 함수(constructor function) 에서 사용된다.

이 말은  지금 보이지 않는 어딘가에 생성자 함수가 존재한다는 말이다. 

그리고 거기서 새로운 object를 찍어낸다는 말이다. (배열도 객체에 포함된다.)

new 옆에 쓰여져 있는 대문자 이름은  Array다.  그 말은 생성자 함수의 이름은 Array 라는거. 

파라미터 값으로 1,2,3,4,5 를 넣어줘서, 자바스크립트는 하나의 배열을 생성해낸다. 

 

이러한 원리로 Array 라는 constructor에 내장된 .sort() , .map(),  .push()  같은 것들을 사용할 수 있는것이다. 

 

 

 

prototype 과 constructor function  둘 다 상속해주는거 아님?? 뭐가 달라? 

constructor function. 즉 생성자 함수는 직접 상속값을 가지도록 한다. 

prototype직접 상속값을 가지고 있지 않고, 그것의 참조값(reference)에 값을 넣어준다.

 

 

 

 

 

 

__proto__

 

생성자 함수를 이용해 만든 object 들은 __proto__ 라는 속성을 가지고 있다. 

어떤 요소의 prototype 을 검색하고 싶을때   __proto__  를 사용한다.

이를 이용해서 prototype 이 없는 배열이나  object  에 prototype 을 강제 등록할 수 있다. (권장되진 않는다. )

 

console.log(학생1.__proto__)  // 출력값 {constructor: ƒ} (출력값 열면 gender: "여")

 

 

var 부모 = {name : 'kim'}
var 자식 = {};
자식.__proto__ = 부모;
console.log(자식.name);  //kim 출력

 

 

아래의 경우 왜 이렇게 될까? 

function Parent(){
  this.name = 'Kim';
}
var a = new Parent();

a.__proto__.name = 'Park';
console.log(a.name)  // 'Kim' 출력.

당연한 결과다. 

a.__proto__.name = 'Park';

이건 부모 prototype { name : 'Park' } 이걸 추가하라는

 

a에 이미  생성자 함수에서 찍어낸 객체를 받았고,

그 객체가 가지고 있는 name 이라는 키가 있기 때문에 이거 먼저 출력해줌.

 

console.log(a); 의 결과값

 

 

 

아니 그래서 prototype 과 __proto__  ?? 뭐가 달라? 

__proto__

  • 객체 자체의 프로토타입 을 가리킴
  • 이걸 이용해서 개별객체가 자신의 부모객체 프로토타입에 접근.
  • 개별 객체에 대한 프로토타입 만 변경함.  (잘 안씀. 상속받거나 속성을 추가함. )
  • 전체 객체에는 영향 없음
  • 생성자 함수로 만들어진 인스턴스에 접근해서 속성 조작 할 때.

 

prototype

  • 모든 생성자 함수는 prototype 속성을 가짐.
  • 생성자 함수를 통해 생성된 모든 객체의 프로토타입을 정의
  • prototype 변경하면 모든 객체에 영향 미침
  • 생성자 함수를 통해 만들어진 모든 객체는 같은 프로토타입을 공유하기 때문.
  • 객체나 배열에서 사용할 수 없다. 자바스크립트에 내장된 생성자 함수를 통해 객체와 배열이 만들어 진 결과물 이기 때문. 
  • 생성자 함수에 접근해서 속성 조작 할 때.