자바스크립트

constructor(생성자)와 prototype 에 대하여.

jdy8739 2021. 12. 27. 23:52

자바스크립트의 생성자는 자바의 클래스에 있는 생성자만을 똑 떼어놓은 느낌이다.

 

자바처럼 클래스안에 존재하는게 아니라,

 

function ConstructorName(name, age) {

    this.name = name;

    this.age = age;

}

 

처럼 함수형식으로 선언된다.

참고로 생성자 함수의 이름은 일반 함수와 다르게 첫글자가 대문자이다.

 

이걸로 const person = new ConstructorName('Jack', 27);

요런 식으로 객체를 만들어주는데 요렇게 생성자로 만들어진 객체

 

'인스턴스'라고한다.

 

진짜 기본 문법은 자바와 거의 같다.

 

function ConstructorName(name, age) {

    this.name = name;

    this.age = age;

    this.greeting = function() {

        console.log(`Hi. My name is ${this.name} and i am ${this.age} years old.`);

    }

}

 

뭐 이렇게 함수를 넣을 수도 있다.

예상가능하겠지만 생성자 안의 thisnew생성되는 인스턴스의 프로퍼티이다.

 

어쨋든 new를 통해 인스턴스를 만들면,

 

만들어진 인스턴스들은 생성자의 내용을 상속받은 자식이고 생성자는 부모라고 불린다.

 

***

여기서 중요한점은 상속을해 물려줄 수 있는 함수나 변수들은 생성자에만 선언해둘 수 있는게 아니다.

***

 

이 개념이 너무 중요한게, 자식 객체에 몰래 물려줄 수 있는 변수나 함수들은 prototype이라는 공간에 저장이되기때문이다!

 

몰래 물려준다는 점은 생성된 인스턴스를 console.log();로 출력했을 때 prototype으로 물려준 값은 보여지지않는다는것이다.

일단 prototype에 함수나 변수를 넣고자한다면...

 

생성자이름.prototype.gender = '남';

 

이런식으로 해준다.

 

사진의 마지막 줄에 보이는것처럼 생성자.prototype.gender = '남'; 이렇게 값을 넣어줘도 일반적인 console.log(인스턴스); 출력으로는 프로토타입에 넣어진 값이 보이지않는다.

 

그러나 console.log(학생1.gender); 처럼 해당 값을 직접적으로 호출했을 때는 제대로 값이 출력된다.

 

즉, prototype은 가지고 있으나 보여지지는 않고, 만약 사용자가 존재를 알고있고 원한다면 가져다 쓸 수 있는 변수나 함수의 모임인것이다. 이것을 주목하자.

 

prototype은 당연히 이것은 생성된 각 인스턴스처럼 개별적인 값을 가질수는 없고 부모 생성자의 prototype이 가진 하나만의 변수나 함수인데, 강의에서는 자식 객체들이 물려받을 수 있는 유전자에 비유하고있다.

 

위 사진에서 보면 객체 형태로 gender와 constructor 값이 key로 존재하는걸 알 수 있다.

 

그럼 이 생성자로 생성된 인스턴스들은 저 gender 프로퍼티를 기본으로 공유하게되는것이다.

 

별로 어렵지않다.

 

하지만 여기서 또 확실하게 짚고 넘어가야할 점은 prototype에 선언된 변수와 함수들은 자식 인스턴스들이 직접적으로 소유하게되는것이 아니라 부모 생성자의 prototype에 구현된 변수와 함수에 접근할 수 있는 권한을 갖는다 라는 개념으로 보아야한다.

 

명심하자. 절대 인스턴스들이 갖는게 아니다. 호출하는것이다!

 

 

그러면 prototype이 적용된 사례를 살펴보자.

 

우리가 흔히 쓰는 배열 자료형 변수에서 push, splice, sort 함수들, 객체 자료형에서 사용하는 수많은 함수들은

우리가 직접적으로 만들어주지않아도 기본으로 쓸 수 있다.

 

우리가 만든 함수나 배열들은 console.log로 출력해봐도 해당 함수를 갖고있지않지만, 우리는 언제든지 원하면 이미 만들어진 함수들을 사용할 수 있지않나.

 

그것은 이미 Array와 Object라는 생성자의 prototype에 해당 함수들이 이미 구현, 저장이 되어있고 우리는 그 생성자를 new 해서 배열, 객체 자료형 변수를 만들기때문이다.

 

우리는 일반적으로 배열을 선언하고 할당할 때

 

const arr = [1, 2, 3, 4];

요렇게 한다.

 

하지만 컴퓨터에서 저 코드는...

 

const arr = new Array(1, 2, 3, 4);

로 읽힌다.

 

결국 Array라는 이미 구현된 생성자를 new 해서 인스턴스로 변수를 만드는것이고,

Array라는 생성자의 prototype에는 우리가 일반적으로 사용하는 함수들이 다 구현이 되어있다.

 

그래서 만들어진 인스턴스들은 부모 생성자의 prototype에 만들어진 함수와 변수를 자유롭게 사용할 수 있다!

 

이게 결론이다.

 

그럼 짧게 작동원리를 적어본다.

 

arr.push(5); 를 입력하면 [1, 2, 3, 4]이 들어있는 배열에 5을 넣는다.

 

근데 내가 방금 만든 arr이라는 변수에는 push()라는 함수가 없다.

 

컴퓨터는 일단 arr이라는 변수에 push라는 함수가 있는지 알아보고, 없다면 부모 생성자의 prototype에 해당 함수가

구현되었는지 확인한다.

 

그럼 있으면 갖다쓰고 없으면 더 상위의 생성자 prototype을 탐색해 찾으면서 계속 위로 올라간다.

 

결국 내가 만든 배열 변수 arr은 Array라는 생성자new Array();하여 만들어진 인스턴스이기때문에

 

부모 생성자인 Array의 프로토타입에 만들어진 push() 함수를 사용할 수 있는것이다.

 

그럼 prototype으로 간접 상속시키는것과 constructor로 직접 상속시키는것의 차이는 무엇일까?

이해는 했고 타자치기 귀찮아서 복붙한다.