오늘은 대망의 프로토타입과 상속에 관하여 물어보았다. 평소에도 대충 알고 있던 내용이라 정리에 큰 도움이 되었다!
// 안녕하세요! 자바스크립트의 프로토타입과 상속 관련 내용 중 자바스크립트의 프로토타입 기반 상속에 대해 자세히 알려주세요.
안녕하세요! 자바스크립트의 프로토타입 기반 상속에 대해서 설명하겠습니다.
자바스크립트는 객체 지향 언어이지만, 클래스 기반 언어와는 조금 다른 특징을 가지고 있습니다.
클래스 기반 언어에서는 클래스라는 청사진을 만들고 이를 기반으로 객체를 생성하지만,
자바스크립트에서는 프로토타입이라는 객체를 만들고 이를 참조하여 다른 객체를 생성합니다.
이런 특징 때문에 자바스크립트를 프로토타입 기반 언어라고도 합니다.
자바스크립트의 모든 객체는 프로토타입이라는 다른 객체를 참조합니다.
객체에 프로퍼티나 메소드를 요청할 때, 해당 객체에 그 프로퍼티나 메소드가 없으면 자바스크립트는
그 객체의 프로토타입에서 그것을 찾습니다.
이것을 프로토타입 체이닝이라고 합니다.
예를 들어, 아래와 같은 코드를 봅시다.
function Person(first, last) {
this.firstName = first;
this.lastName = last;
}
Person.prototype.getFullName = function() {
return this.firstName + " " + this.lastName;
}
var myPerson = new Person("John", "Doe");
console.log(myPerson.getFullName()); // "John Doe"
여기서 Person 함수는 생성자 함수이며, getFullName 메소드는 Person의 프로토타입에 추가되었습니다.
new Person("John", "Doe")로 새로운 객체를 생성하면, 이 객체는 Person의 인스턴스가 되며,
Person의 프로토타입에 정의된 메소드를 상속받습니다.
이렇게 프로토타입 체이닝을 통해 객체 간에 메소드와 프로퍼티를 공유하고 상속하는 것이 자바스크립트의 프로토타입 기반 상속입니다.
// 이 부분에서 제가 궁금했던 것은, 방금 예시로 보여준 코드에서 Person은 함수잖아요? 그런데 new 키워드를 사용해서 마치 class 문법 처럼 new Person() 으로 사용할 수 있는데, class 문법과 function 문법 이 둘 사이의 차이가 잘 이해가 안되었어요.
그렇습니다, 자바스크립트에서 함수는 일급 객체로 취급되며, 함수를 이용하여 마치 클래스와 비슷한 방식으로 객체를 생성할 수 있습니다. 이는 자바스크립트가 클래스 기반 언어와 프로토타입 기반 언어의 특징을 모두 가지고 있다는 점을 보여줍니다.
클래스 기반 언어에서, 클래스는 객체의 청사진이며 new 연산자를 사용하여 클래스의 인스턴스를 생성합니다.
이때, 생성자 함수가 호출되어 객체의 초기화를 담당합니다.
자바스크립트에서는 "함수"가 이 클래스와 비슷한 역할을 하며, new 연산자를 사용해 함수를 생성자로 사용할 수 있습니다.
생성자 함수를 호출하면 새로운 객체가 생성되고, 이 객체는 생성자 함수의 prototype 속성을 참조하는 프로토타입이 설정됩니다.
자바스크립트에서 new 연산자를 사용해 함수를 호출하면 다음과 같은 일이 일어납니다:
- 새로운 빈 객체가 생성됩니다. {}와 같은 빈 객체입니다.
- 이 객체의 프로토타입이 설정자 함수의 prototype 객체로 설정됩니다.
- 생성자 함수가 호출되며, 이때 this는 새로 생성된 객체를 가리킵니다.
- 만약 생성자 함수에서 명시적으로 객체를 반환하지 않으면, this가 자동으로 반환됩니다.
그러나 클래스와 함수를 사용한 생성자 사이에는 중요한 차이가 있습니다. ES6에서 도입된 class 키워드는 문법적 설탕(syntactic sugar)으로, 프로토타입 기반 상속을 보다 쉽게 이해하고 사용할 수 있도록 도와줍니다.
하지만 내부적으로는 여전히 프로토타입 기반으로 작동합니다.
요약하자면, 자바스크립트의 함수는 new 연산자를 사용하여 생성자로 사용될 수 있으며, 이는 객체 생성에 유연함을 제공합니다.
그러나 이는 여전히 프로토타입 기반의 상속 모델을 따르며, class 문법은 이를 더 쉽게 다루기 위한 문법적 설탕입니다.
// 오호 그렇군요. 저는 그냥 함수 문법에서는 contstructor 라던지 super 라던지 extend 같은 것을 쓰는 일이 없어서, ES6의 class 문법은 문법적 설탕이 아닌 새로운 것인 줄 알았어요. 그러면 기존의 function 문법으로도 constructor super 등을 구현할 수 있는 것이네요?
네, 맞습니다. 사실상 ES6 클래스 문법의 constructor, super, extends와 같은 개념들은 기존의 자바스크립트 함수와 프로토타입을 이용해서 구현할 수 있습니다. 하지만 그 과정은 비교적 복잡하고 에러를 유발하기 쉬워, ES6에서는 이를 단순화하고자 class 문법을 도입하였습니다.
예를 들어, super와 extends는 상속을 구현할 때 사용됩니다. 자바스크립트 함수와 프로토타입으로 이를 구현하는 방법은 아래와 같습니다:
function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}
function Dog (name) {
Animal.call(this, name); // super(name)
}
Dog.prototype = Object.create(Animal.prototype); // Dog extends Animal
Dog.prototype.speak = function () {
console.log(this.name + ' barks.');
}
var d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
이 코드에서, Animal.call(this, name);은 기본 클래스의 생성자를 호출하는 것과 같은 역할을 합니다.
이것은 super 키워드와 같은 역할을 합니다. 또한, Dog.prototype = Object.create(Animal.prototype);은 Dog이 Animal을 상속받도록 합니다. 이것은 extends 키워드와 같은 역할을 합니다.
하지만 이 코드는 비교적 복잡하고, 실수하기 쉬운 여러 부분들이 있습니다.
따라서 ES6에서는 class, constructor, super, extends 등의 새로운 문법을 도입하여 이를 단순화하였습니다.
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak(); // Mitzie barks.
이렇게 class 문법을 사용하면 더 간결하고 이해하기 쉬운 코드를 작성할 수 있습니다.
그러나 내부적으로는 여전히 프로토타입 기반의 상속이 작동하고 있음을 기억해야 합니다.
// 나의 허접한 질문에도 성심성의껏 대답해준 선생님이다...
'javascript' 카테고리의 다른 글
[자바스크립트 30] 프로토타입과 상속 3 - 클래스 (0) | 2023.06.14 |
---|---|
[자바스크립트 29] 프로토타입과 상속 2 - 생성자함수 (0) | 2023.06.14 |
[자바스크립트 27] 비동기 3(async/await) (1) | 2023.05.13 |
[자바스크립트 26] 비동기 2(프로미스) (0) | 2023.05.13 |
[자바스크립트 25] 비동기 1(콜백함수) (0) | 2023.05.13 |