[js] 생성자 함수와 prototype 메서드

OrganCow·2023년 9월 13일
0

null_hub

목록 보기
2/14
post-thumbnail

이 글은 Dev quiz 어플리케이션 null의 퀴즈 해설을 위한 글입니다.
보러가기 -> https://github.com/0hhanum/null_ios

question:
  - 빈칸에 들어갈 말은?
  - "
    <code>
    function Person() {
        ...
        this.getName = function() {
            return this.name;
        }
    }
    </code>
    "
  - 생성자 함수 작성 시 메모리 측면에서 위 방식은 적합하지 않습니다. 
  - 해당 함수의 ______을 이용하는 것이 좋습니다.
answer:
  - prototype

prototype?

객체

prototype에 대해 설명하려면 객체에 대해 알아야 합니다.
흔히 JavaScript에서 거의 모든 것이 객체라고 설명합니다.

JS의 요소는 객체와 원시 타입(primitive type)으로 나눌 수 있습니다.

[원시 타입]
1. 문자열 (string)
2. 숫자 (number)
3. 불리언 (boolean)
4. null
5. undefined
6. symbol (ES6부터 도입된 고유 식별자)

위 타입을 제외한 JS 내의 모든 요소가 객체입니다. (함수, 배열, 정규표현식, 에러, etc)

const arr = [1,2,3] // Array의 객체
const hanum = new Person(); // Person의 객체

JavaScript는 프로토타입 기반 언어

위 문구를 한 번쯤은 들어보셨을 겁니다.

모든 객체는 프로토타입 객체(prototype object)를 가지며 자신의 프로토타입 객체에 정의된 속성에 접근할 수 있다는 뜻입니다.

예를 들어 Array 객체의 프로토타입은 forEach(), map() 등의 메서드를 가지고 있기 때문에 [].forEach() 와 같은 형식으로 메서드를 사용할 수 있습니다.

생성자 함수를 사용할 경우, 아래와 같이 프로토타입 메서드를 정의합니다.

function Person(name){
  this._name = name;
}
Person.prototype.getName = function() {
  								return this._name
							}

const hanum = new Person("hanum");
hanum.getName();

프로토타입 객체에 메서드를 정의하는 것과 일반 메서드를 정의하는 것은 어떻게 다를까요?

prototype 객체는 인스턴스 내부에 존재하지 않습니다.
인스턴스 외부에 별도 객체에 저장되어 있죠.

퀴즈 문제처럼 일반 메서드를 이용한다면

function Person(name) {
  this.name = name;
  this.getName = function() {
                      return this.name
                   }

const p1 = new Person("p1");
const p2 = new Person("p2");

p1, p2가 생성될 때마다 getName() 함수를 생성해야 하므로 자원이 낭비될 뿐더러, p1과 p2 내부에 각각 getName()대한 정보를 저장합니다. 기능은 같지만, 각 인스턴스에 새로운 메서드를 추가했을때와 동일하게 동작합니다. 아래처럼요.

p1.someFunc = () => {};
p2.otherFunc = () => {};

이는 메모리 관리에 비효율적입니다.

위의 prototype 설명의 예시처럼 prototype 객체에 getName()을 정의한다면, p1p2에서 동일한 prototype 객체의 getName()을 이용하게 됩니다.

인스턴스 내부에 함수가 저장되지 않으므로 객체가 가벼워지죠.
따라서 문제 상황의 경우 prototype을 이용하는 것이 유리합니다.

그 외에도 일반 메서드가 아닌 프로토타입 메서드를 사용한다면

  • 프로토타입 체인을 통한 상속
  • 동적 업데이트 (일반 메서드의 경우 인스턴스 생성 이후 메서드 업데이트 불가능)
  • 코드 가독성 향상 (객체 property로 프로토타입 메서드가 표시되지 않음)

등의 장점이 있으니, 상황에 맞게 잘 사용하는 것이 좋습니다.

class 문을 사용한다면?

ES5에서 추가된 class문을 사용하면 훨씬 직관적으로 프로토타입 메서드를 작성할 수 있습니다.
class문 또한 완전히 새로운 것이 아닌 프로토타입 기반의 syntax sugar이기 때문이죠.

class Person {
  constructor(name) {
    this.name = name;
  }
  getName() {
    return this.name
  }
}

사실 위의 코드는

class Person {
  constructor(name) {
    this.name = name;
  }
}
Person.prototype.getName = function() {
  								return this.name
							}

와 동일합니다. 하지만 객체 메서드를 사용하는 전자가 훨씬 직관적입니다. 재미있죠?

참조

0개의 댓글