프로토타입

김동영·2025년 3월 28일

자바스크립트

목록 보기
6/7
post-thumbnail

자바스크립트는 프로토타입 기반 언어이다.

  • 클래스 기반 언어에서는 상속을 사용하지만 프로토타입 기반 언어에서는 어떤 객체를 원형 으로 삼고 이를 복제(참조)함으로써 상속과 비슷한 효과를 얻습니다.

아래의 그림을 보면 프로토타입에 대해서 알 수 있습니다.

왼쪽 꼭짓점에는 Constructor(생성자 함수)

오른쪽 꼭짓점에는 Constructor.prototype 이라는 프로퍼티를

왼쪽 꼭짓점으로부터 아래를 향한 화살표 중간에 new가 있고 종점에는 instance가 있고

오른쪽 꼭짓점에서 대각선 아래향하는 화살표 종점에는 instance.__proto__ 라는 프로퍼티가 있습니다.

  • 어떤 생성자 함수를 new 연산자와 함께 호출하면 Constructor에서 정의된 내용을 바탕으로
    새로운 인스턴스가 생성된다.
  • 이때 instance에는 __proto__라는 프로퍼티가 자동으로 부여되는데
    이 프로퍼티는 Constructorprototype이라는 프로퍼티를 참조한다.

여기서 prototype__proto__가 등장하는데 이 둘의 관계가 프로토타입의 핵심 개념입니다.

prototype와 이를 참조하는__proto__는 모두 객체이고
prototype 객체 내부에는 인스턴스가 사용할 메서드를 저장합니다.
그러면 instance 에서도 숨겨진 프로퍼티인 __proto__ 를 통해 이 메서드들에 접근할 수 있습니다.

코드예시

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

const suzi = new Person('Suzi');
suzi.__proto__.getName(); // undefined

다음과 같은 코드를 보시면
Person 함수 를 통해 인자로 받은 name 값을 _name 속성값으로 가지고,
Person.prototype 프로퍼티에 getName 함수를 추가했습니다.

이후 Person 함수를 생성자로 사용해서 suzi 라는 인스턴스를 생성하여

suzi.__proto__.getName(); 을 했을때 에러가 아닌 undefined가 출력되는것을 볼 수 있습니다.

그 이유는 suzi 인스턴스에는 __proto__라는 프로퍼티가 자동으로 부여되어 Person.prototype 이라는 프로퍼티를 suzi.__proto__가 참조하고있지만
this 바인딩이 잘못되어 있기 때문입니다.

그럼 만약에 __proto__ 객체에 name프로퍼티가 있으면?

	const suzi = new Person('Suzi');
	suzi.__proto__.name= 'suzi__proto__'
	suzi.__proto__.getName(); //suzi__proto__

예상대로 나오는것을 볼 수 있습니다.

그렇다면 this를 인스턴스로 하는 방법은 없을까요??
그 방법은 __proto__ 없이 인스턴스에서 곧바로 메서드를 사용하는것 입니다.

	const suzi = new Person('Suzi');
	suzi.getName(); //Suzi
	const iu = new Person('IU');
	iu.getName(); //IU

다음과 같이 나오는 이유는 __proto__ 가 생략 가능한 프로퍼티이기 때문입니다.

그래서 다음과 같은 그림이 나오게 된것입니다.

이미지 출처 :https://d-sup.github.io/core%20javascript/TIL-prototype/

결론

자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성해 놓는데
new 연산자와 함께 함수를 호출할 경우 __proto__ 가 자동으로 생성되며 prototype 참조합니다.
__proto__ 프로퍼티는 생략이 가능하도록 구현돼 있기 때문에
생성자 함수의 prototype에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 접근할 수 있습니다.

프로토타입 체인

메서드 오버라이드

만약 프로토타입 객체와 인스턴스가 동일한 이름의 프로퍼티 또는 메서드를 가지는 상황이라면 어떻게 될까요??

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

const iu = new Person('지금');
iu.getName = function(){
	return '바로' + this.name;
}
console.log(iu.getName()) // 바로 지금

iu.__proto__getName이 아닌 iu 객체에 있는 getName 메서드가 호출되었습니다.
이러한 현상을 메서드 오버라이드라고 합니다.

가장 가까운 대상인 자신의 프로퍼티를 검색하고 없으면 그 다음으로 가까운 대상인 __proto__를 검색하는 순서로 진행되는 것입니다.

이런식으로 단계가 하나만 있는것이 아니라 여러개도 가능하여 __proto__ 에서 __proto__ 로 연쇄적으로 이어진 것이 프로토타입 체인 입니다.

객체 전용 메서드의 예외사항

  • 어떤 생성자 함수든 prototype은 반드시 객체이기 때문에 Object.prototype이 언제나 프로토타입 체인의 최상단에 존재합니다.
  • 그렇기 때문에 객체에서만 사용할 메서드는 다른 데이터 타입처럼 프로토타입 객체 안에 정의할 수 없다.
    왜냐하면 객체에서만 사용할 메서드를 Object.prototype 에 정의한다면 다른 데이터 타입도 해당 메서드를 사용할 수 있기 때문입니다!

그래서 객체만을 대상으로 동작하는 객체 전용 메서드들은
Object.prototype 이아닌 Object 스태틱 메서드로 되어있습니다.

ex) Object.freeze

예외적으로 Object.create(null)을 사용하면 __proto__ 가 없는 객체를 생성합니다!

profile
안녕하세요 프론트엔드개발자가 되고싶습니다

0개의 댓글