'프로토타입과 프로토타입 체인에 대해 아는 대로 설명 부탁드립니다.'
최근에 기술 면접을 보면서 Javascript의 프로토타입에 대한 질문을 받았습니다. 평소 프로토타입에 대해 완전히 이해하지 못하고 있었기 때문에 결국 어정쩡하게 둘러댈 수밖에 없었는데요.
이번 글에서는 그때의 상황을 돌아보며, Javascript의 프로토타입에 대해 제대로 다시 공부하고 이해한 내용을 공유하려고 합니다.
Javascript와 Prototype
클래스(Class)는 객체지향에서 중요한 개념입니다. 때문에 대부분의 객체지향 언어(e.g. Java, C++)에서는 이러한 클래스가 기반이 되지만, Javascript는 객체지향 언어이긴 하나, 그 기반이 프로토타입(Prototype-Based)이 됩니다. 즉, 클래스 없이도 객체를 생성할 수 있다는 뜻 입니다.
그렇다면, 프로토타입은 정확히 무엇일까요?
Javascript에서 모든 객체는 생성 시 자신을 만들어낸 객체의 원형에 대한 숨겨진 연결을 갖습니다. 프로토타입이란, 여기서 언급되는 '자신을 만들어낸 객체의 원형'입니다. 다시 말해, 프로토타입은 어떠한 객체가 만들어지기 위해서 그 객체의 원형이 되는 객체이며, 이러한 프로토타입을 통해 객체의 프로퍼티나 메서드에 대한 상속 기능을 흉내낼 수 있게 되는겁니다.
다음은 명확한 이해를 위한 간단한 예제입니다.
// 기본 객체 생성
const person = {
name: 'Unknown',
greet: function() {
console.log(`Hello, my name is ${this.name}`);
}
};
const student = Object.create(person);
// 프로퍼티 설정
student.name = 'Alice';
// 사용 예시
student.greet(); // Output: Hello, my name is Alice.
예제에서 'Student' 객체는 'Person' 객체의 메서드인 'greet'를 호출합니다.
이것이 가능한 이유는 'Person'으로부터 생성된 객체(Student)는 Person.prototype(원형 객체)의 프로퍼티와 메서드를 사용할 수 있기 때문입니다. 이것이 JavaScript의 프로토타입 상속 메커니즘이며, 따라서 'Student' 객체는 'Person' 객체에 정의된 'greet' 메서드를 호출할 수 있습니다.
심화 과정
프로토타입에 대한 감을 어느정도 익혔다면, 이제 조금 더 핵심적인 개념을 알아보겠습니다. 바로 Prototype Object와 Prototype Link입니다. 프로토타입은 이 둘을 통합한 개념이기도 합니다.
Prototype Object
Prototype Object(프로토타입 객체)란 객체가 상속받는 프로퍼티와 메서드를 정의하는 객체입니다.
위의 사진에서는 Prototype Object에 'constructor'(생성자)와 '__proto__'가 있고, 'prototype' 프로퍼티는 Prototype Object를, 'constructor' 프로퍼티는 'Person' 함수 객체를 가리키고 있습니다.
그렇습니다. 위의 사진처럼, Prototype Object는 일반적인 객체이며 'constructor', '__proto__'를 기본적인 프로퍼티로 가집니다. 또 Javascript에서 모든 함수는 'prototype'이라는 프로퍼티를 가지며, 이 'prototype'이라는 프로퍼티를 통해 Prototype Object에 접근할 수 있습니다.
그렇다면 이제 'constructor'와 '__proto__'를 알아볼 차례입니다.
먼저 constructor입니다.
constructor는 왜 Person 함수를 가리키고 있을까요? 그 이유는 아래의 코드와 함께 확인할 수 있습니다.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const alice = new Person('Alice');
console.log(alice.constructor === Person); // true
코드에서 'alice.constructor'는 'Person'을 가리킨다는 사실을 확인할 수 있습니다.
정답은 여기에 있습니다. 결국 constructor가 Person 함수 객체를 가리키는 이유는, 해당 Prototype Object가 어떤 생성자 함수에 의해 생성되었는지를 Prototype Object가 알게하기 위함입니다.
최종적으로 constructor는 기본적으로 자신(Prototype Object)을 생성한 생성자 함수를 추적할 수 있게 하고, 객체의 타입 체크에도 도움을 줍니다.
그렇다면 이제 '__proto__'가 남았는데요. 제가 글의 앞 부분에서 'Prototype Object와 Prototype Link. 프로토타입은 이 둘을 통합한 개념이기도 합니다.' 라는 말씀을 드렸었습니다.
이 부분을 다시 꺼내는 이유는, 여기서 이 '__proto__'가 Prototype Link를 의미하기 때문입니다.
Prototype Link
이번에도 개념을 이해하기 전에 간단하게 예제를 살펴보겠습니다.
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name}`);
};
const alice = new Person('Alice');
console.log(alice); // Output: Person {name: 'Alice'}
alice.greet(); // Output: Hello, my name is Alice
예제에서, 'alice'는 'Person'의 Prototype Object를 참조합니다.
Prototype Link란, 쉽게 말해 객체가 자신이 참조하는 Prototype Object와 연결이 되는 내부 링크입니다.
'alice'는 'Person'으로부터 생성이 되었고, 이 때문에 'Person'의 Prototype Object와 내부적으로 연결되며, 따라서 'alice'는 'Person.prototype'에 정의된 'greet' 메서드를 호출할 수 있습니다.
여기서 또 하나의 개념을 찾을 수 있습니다.
결국, 'alice'는 'greet' 메서드를 직접적으로 가지고 있진 않았지만, 'greet' 메서드를 상위 Prototype Object에 접근하여 호출하였는데요. 이런 식으로 객체가 특정 프로퍼티나 메서드를 찾을 때, 먼저 자신의 프로퍼티에서 찾고, 없으면 Prototype Link를 통해 상위 Prototype Object에 접근하는 것을 Prototype Chain(프로토타입 체인)이라고 합니다.
이렇게 계속 상위 프로토타입을 탐색하는 과정에서, 최상위 Object의 Prototype Object까지 도달했음에도 불구하고 찾고자 하는 프로퍼티나 메서드를 찾지 못했을 경우에는 undefind를 반환합니다.
도움이 된 글
https://medium.com/@bluesh55/javascript-prototype-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-f8e67c286b67
https://poiemaweb.com/js-prototype
'Web Frontend > Javascript' 카테고리의 다른 글
라이브러리 없이 uuid 생성하기 (4) | 2024.01.11 |
---|---|
Javascript 동작 원리 파악하기 (0) | 2023.05.03 |