본문 바로가기
JS/JavaScript 강의

[JS] 61. 생성자 함수와 new 연산자/프로토타입 상속과 체인

by GiraffePark 2023. 1. 11.

안녕하세요. 박기린 입니다.

이번엔 객체 지향 프로그래밍(OOP - Object Oriented Programming)의 class를 생성하는 방법에 대해 알아보겠습니다.

 

 

 

생성자 함수와 new 연산자

자바스크립트에서는 생성자 함수와 new 연산자를 이용해서 class를 생성할 수 있습니다. 이 방식은 JavaScript의 구식 방식으로, 앞으로 소개해드릴 모든 자바스크립트 class 생성 방법의 근간이 되는 방식입니다. 다른 언어와는 다른 부분이 많다보니 헷갈릴 수도 있습니다.

 

 

const Person = function(firstName, birthYear) {
    // Instance properties
    this.firstName = firstName;
    this.birthYear = birthYear;
};

const giraffe = new Person('Giraffe', 2023); // 인스턴스 생성 예시
console.log(giraffe);
Person은 해당 클래스의 생성자 함수(Constructor Fuction)가 됩니다.

- 생성자함수의 이름은 convention에 따라 항상 대문자로 시작합니다.
- arrow function(화살표 함수)는 this 키워드를 사용할 수 없어, class의 properties를 지정할 수 없습니다. 따라서 function 표현식을 사용합니다.
- 생성자 함수와 일반 함수 간의 가장 큰 차이점은, 생성자 함수는 new 키워드를 사용해서 생성자를 호출하다는 것입니다.

실행결과물

 

 

 

 

 


생성자 함수의 작동방식

생성자 함수의 작동 4단계
1. new 키워드에 따라 {빈 객체} 가 생성됩니다.
2. 생성자 함수의 this 키워드로 {빈 객체}가 불러와집니다. 그리고 생성자 함수의 인수로 받은 값을 {빈 객체} 인스턴스 properties로 지정합니다. 
3. {인스턴스가 된 객체}는 __proto__라는 property가 생성되고, 거기에 생성자.prototype이 연결됩니다.
4. properties가 지정되고 나면, 자동으로 {properties가 담긴 객체}가 return 됩니다.
 -> 생성자 함수는 따로 return을 지정할 필요 없이, new 연산자를 통해서 객체를 return 합니다.

 

알 수 없는 용어들이 많이 등장한 거 같아, 차근차근 다시 정리해보겠습니다.

- 인스턴스는 생성자 함수를 이용해서 찍어낸 객체를 의미합니다. 위의 코드에서 giraffe는 Person Class의 인스턴스입니다.

- 프로토타입(prototype)은 특정 생성자 함수에 의해 생성된 모든 인스턴스가 함께 공유하는 원형입니다. 

 

이 방식은 마치 생성자 함수로부터 본을 뜨는 것 같은 모습입니다. 생성자 함수의 원형이 {빈 객체} 안에 저장된 뒤에, 그 원형에 따라 인스턴스가 생성되는 방식이기 때문입니다. 이때 자바스크립트에서는 prototype(원형)이라는 단어를 사용합니다. 위의 giraffe 상수는 Person()의 원형을 복사한 후 생성된 인스턴스입니다. 따라서 giraffe는 Person의 prototype(프로토타입)을 상속 받았다고 말합니다. 실제로 위의 실행결과물 사진을 보시면, 하단에 Prototype이라는 용어를 확인할 수 있고, 그 안에 생성자 함수의 구성도 확인할 수 있습니다.

 

 

 

 


프로토타입

메소드 선언하기

Person.prototype.calcAge = function () {
    console.log(2037 - this.birthYear);
};
console.log(Person.prototype); // constructor(Person 원형의 property가 담김)와 calcAge가 들어있음.

생성자함수의_이름.prototype을 이용해서 해당 class의 prototype을 확인할 수 있습니다.

그리고 위의 코드처럼, 뒤에 .메소드_이름을 적고 함수를 선언해서 메소드를 선언해줄 수 있습니다.

 

 

 

 

그러면 해당 프로토타입을 공유하는 모든 인스턴스가 메소드에 접근할 수 있게 됩니다.

 

 

 

 

 

 

인스턴스의 프로토타입을 확인하기

console.log(giraffe.__proto__); //calcAge가 들어있음
console.log(giraffe.__proto__ === Person.prototype); // true
console.log(Person.prototype.isPrototypeOf(giraffe)); // true

실행결과물

class의 경우 Person.prototype을 이용해서 프로토타입을 확인했다면, 인스턴스는 __proto__ property를 이용해서 프로토타입을 확인할 수 있습니다.

 

 

 

 

 

 

 


프로토타입 상속

출저 : https://www.udemy.com/course/the-complete-javascript-course/

프로토타입의 상속과정을 도식화하면 위와 같은 모습입니다.

1. giraffe는 Person 생성자 함수에 의해서 name, birthYear이라는 property가 생성됩니다.
2. giraffe는 new 생성자에 의해서 Person의 프로토타입 객체의 주소를 상속받습니다.
3. Person.prototype에 calcAge()라는 함수가 생성됩니다.
4. giraffe.calcAge()가 실행되면, Persone.prototype의 주소로 이동해서 caclAge()라는 메소드가 있는지 찾습니다. 메소드를 찾으면 실행이 됩니다.

 

 

 

 

 


금지사항

const Person = function(firstName, birthYear) {
    // Instance properties
    this.firstName = firstName;
    this.birthYear = birthYear;


    this.calcAge = function() {
        console.log(2022 - this.birthYear);
    };
};

위의 코드처럼 생성자 함수 내부에 메소드를 만들지 마세요. 위의 코드처럼 코딩을 해도 정상작동 하지만, 좋은 방법은 아닙니다.

이 방식은 메소드가 인스턴스에 저장되는 방식입니다. 만약에 Person에 method가 천 개 정도 있다고 한다면, 인스턴스를 생성할 때마다 천 개의 메소드 복사본이 같이 저장됩니다. 

이 방식보다는, 위에서 설명드린 prototype에 메소드를 한 번 선언한 후에 그 주소를 따라서 메소드에 접근하는 방식을 사용합시다.

 

 

 

 

 


프로토타입 체인

Person의 인스턴스인 giraffe를 살펴보면, [[Prototype]]이 두 개가 보입니다.

하나는 Person.prototype이라는 것을 알겠는데, 나머지 하나는 무엇일까요?

 

 

 

 

정담은 바로 Object.prototype입니다. 생성자 함수가 Object()이기 때문입니다.

Object는 데이터 타입의 하나로 알고 있었는데, 왜 Object의 prototype이라고 하는 걸까요?

 

 

 

 

 

 

출저 : https://www.udemy.com/course/the-complete-javascript-course/

사실 모든 Object는 Object.prototype을 상속받고 있습니다. 그렇기에 우리가 Object의 내장 메소드를 사용할 수 있는 것입니다.

제 글 중에도 Array나 Object의 내장 메소드들에 대해 설명을 드렸었는데, 

 

 

 

 

 

 

Array와 Object 모두 Prototype으로 내장메소드를 전달하기 때문입니다.

 

 

 

 

const arr = [3, 6, 6, 5, 6, 9, 9]; // new Array === []
console.log(arr.__proto__); // Array.prototype -> Array 내장함수들
console.log(arr.__proto__ === Array.prototype); // true

그래서 실제로 Array.prototype이랑 비교를 해보면 true 값이 return 됩니다.

 

 

 

 

console.log(giraffe.__proto__.__proto__ === Object.prototype);

giraffe의 프로토타입은 Person.prototype이고, Person.prototype의 프로토타입은 Object.prototype이기에 위와 같은 코드에서도 true가 도출됩니다.

 

이렇게 여러 프로토타입이 연결된 모습을 보고 프로토타입 체인이라고 합니다.

반응형