[Javascript] 프로토타입

Bam·2022년 2월 26일
0

Javascript

목록 보기
54/106
post-thumbnail

객체

내장 객체 때도 설명했지만 객체는 속성(프로퍼티)와 행위(메소드)를 가지는 개념입니다. 그리고 이러한 개념에 명칭을 부여할 수 있어야하기도 합니다.

자바스크립트에서 객체는 객체 리터럴 방식으로 생성했습니다.

let car = {
	name: 'sedan',
   	color: 'yellow',
    	drive: function() {
    		console.log("부릉");
    	}
}

console.log(car.name);
car.drive();

객체 리터럴 방식은 객체를 만들기 위해서는 요소들을 일일히 새로 입력해야하고, 런타임 때 객체 생성이 어렵다는 점을 가지고 있습니다. 그래서 다른 객체지향언어들에는 클래스 개념을 도입해서 쉽게 객체를 생성할 수 있게 해주는데, 자바스크립트에는 클래스라는 개념이 존재하지 않습니다.

대신, 자바스크립트에는 프로토타입(prototype)이라는 개념이 존재합니다.

프로토타입

프로토타입이란 어떤 객체의 원본이 되는 객체입니다. 자바스크립트는 이 프로토타입을 기반으로 객체들을 생성할 수 있습니다. 그래서 자바스크립트를 객체지향 언어가 아닌 프로토타입 기반 언어라고 부르기도합니다.

기존 언어를 배우신 분들이라면 클래스와 혼동될 수 있는데, 사실 클래스와 큰 차이점은 없습니다. 다만 프로토타입은 클래스에 비해 좀 더 자유를 주는 개념이라고 생각해도 좋습니다.

그러면 자바스크립트의 프로토타입을 하나 정의해보겠습니다.

const Student = function() {}

그냥 함수 리터럴을 쓴거 아니냐고 할 수도 있는데, 맞습니다. 자바스크립트는 클래스 개념이 없기 때문에 함수에 클래스 역할을 부여할 수 있습니다. 그래서 위와같은 클래스는 다음과 같이 인스턴스화를 할 수 있습니다. 참고로 함수 리터럴로 프로토타입을 정의하지만, 애로우 함수로는 프로토타입을 정의할 수 없습니다.

let std = new Student();

생성자

new 연산자를 사용할 때 생성자에 대해 간략히 언급했었습니다. 생성자는 객체를 생성(인스턴스화)할 때 객체의 초기화를 하는 특수 메소드입니다.

그러면 프로토타입에 생성자를 만들어보겠습니다.

const Student = function(name, id) {
  this.name = name;
  this.id = id;
}

let std = new Student('짱구', 001);

this라는 것이 존재하는데, this는 생성자로 생성되는 인스턴스, 즉 객체 자기 자신을 가리치는 키워드입니다. 이 this는 다양한 해석이 존재하므로 나중에 심도있게 다룰 예정이니, 지금은 this가 인스턴스 객체 자기 자신을 가리킨다고만 알아두세요.

그래서 this.name에 생성시 전달한 인수 name을 넣음으로써 객체의 프로퍼티가 초기화 되는 것 입니다. 이것이 생성자이고, 초기화입니다.

방금 프로퍼티를 선언했으니 이번엔 메소드를 선언해보겠습니다. 메소드도 동일한 방법으로 선언합니다.

const Student = function(name, id) {
  this.name = name;
  this.id = id;
  
  this.getName = function() {
    return this.name;
  }
}

let std = new Student('짱구', 001);

메소드의 동적 추가

메소드를 나중에 동적으로 추가할 수도 있습니다. 방금 전의 예시 코드의 getName 메소드를 동적 추가하는 식으로 바꿔보겠습니다.

const Student = function(name, id) {
  this.name = name;
  this.id = id;
}

let std = new Student('짱구', 001);

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

인스턴스를 생성하고, 메소드를 추가하는 방식으로 넣으면 동적으로 메소드를 추가할 수 있습니다. 하지만 이 방법엔 문제가 있습니다.

let std = new Student('짱구', 001);

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

let std2 = new Student('흰둥이', 002);
console.log(std2.getName());  //에러!!!

같은 프로토타입으로 만들어낸 인스턴스일지라도 멤버가 완전히 동일하다고는 보장하지 못합니다. 위의 경우 std에는 getName 메소드가 있지만, std2에는 getName 메소드가 선언되지도 않은 상태라는 것 입니다.

그래서 std2에 대해서도 getName을 사용하기 위해서는 따로 멤버를 정의해야합니다. 하지만 이과정에서 쓸데 없는 프로퍼티와 메소드가 복사되어 메모리 공간을 낭비합니다. 이러한 문제점을 해결하고자 prototype 프로퍼티가 등장하였습니다.

prototype 프로퍼티

프로토타입명.prototype.멤버명 = ;

prototype 프로퍼티는 객체에 멤버를 안정적이게 추가하기 위해 생긴 프로퍼티입니다. prototype을 통해서 멤버를 추가하게 되면, 그 객체의 프로토타입에 멤버가 추가되어, 해당 프로토타입을 기반으로 인스턴스화된 인스턴스들은 모두 추가된 멤버에 접근할 수 있습니다.

말로만 하면 어려우니 다음 예제코드를 보겠습니다. 위에서 작성한 코드를 prototype 프로퍼티를 통해 멤버를 추가하는 모습입니다.

const Student = function(name, id) {
  this.name = name;
  this.id = id;
}

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

let std = new Student('짱구', 001);

prototype 사용시 장점

우선 메모리 절감이 가장 큰 장점입니다. 인스턴스화를 시킬 경우 원본 프로토타입에서 참조만 할 뿐 인스턴스에는 복사되지 않기 때문에 메모리 공간을 상당히 아낄 수 있습니다.

두 번째 장점은 인스턴스가 프로토타입을 실시간으로 참조하고있으므로 변화를 빠르게 인지할 수 있다는 점이 있습니다.

0개의 댓글