📘 16.1.3 __proto__와 prototype - 두 친구의 다른 역할
초등학교 때, 짝꿍과 함께 앉아 있던 기억이 있나요? 이름이 비슷한 두 친구가 있었어요. 민지와 민수처럼 말이에요. 이름은 비슷했지만 성격도 다르고, 잘하는 것도 달랐죠. 민지는 그림을 잘 그렸고, 민수는 수학을 잘했어요.
자바스크립트에도 그런 두 친구가 있어요. __proto__와 prototype이라는 친구들이에요. 이름이 비슷해서 처음에는 헷갈리기 쉽지만, 알고 보면 완전히 다른 역할을 하는 특별한 친구들이랍니다.
오늘은 이 두 친구의 차이점과 각자의 특별한 능력에 대해 함께 알아보려고 해요. 마치 쌍둥이처럼 비슷해 보이지만 서로 다른 개성을 가진 두 친구 이야기처럼 말이에요!
🧠 새로운 단어들과 친해지기
프로토타입의 두 얼굴을 이해하는 데 도움이 되는 용어들을 쉽게 풀어서 설명해드릴게요.
| 단어 | 쉬운 설명 |
|---|---|
| proto | 모든 객체가 가지고 있는 특별한 연결고리로, 자신의 부모(프로토타입)를 가리키는 화살표와 같아요. |
| prototype | 생성자 함수가 가지고 있는 설계도 상자로, 그 함수로 만들어질 객체들이 사용할 기능들을 모아둔 곳이에요. |
| constructor | 자신을 만든 생성자 함수를 가리키는 특별한 속성으로, "나를 만든 공장이 어디지?"를 알려주는 표시예요. |
__proto__는 "던더 프로토"라고 읽어요. "던더(dunder)"는 "double underscore(밑줄 두 개)"를 줄인 말이에요. 마치 비밀 암호처럼 앞뒤로 밑줄이 두 개씩 있어서 특별해 보이죠?
✨ __proto__와 prototype의 핵심 개념
이 두 친구는 자바스크립트에서 객체들이 서로 연결되고 기능을 공유하는 방법을 만들어주는 중요한 역할을 해요. 하지만 각각의 역할은 완전히 달라요.
__proto__는 모든 객체가 가지고 있는 특별한 연결선이에요. 마치 아이가 "내 엄마는 누구야?"라고 물어볼 때 가리키는 손가락과 같아요. 이 연결선을 따라가면 자신이 어떤 기능들을 물려받았는지 알 수 있어요.
반면 prototype은 생성자 함수만이 가지고 있는 특별한 상자예요. 이 상자 안에는 "내가 만들어낼 객체들이 사용할 수 있는 모든 기능들"이 담겨 있어요. 마치 할머니가 가진 레시피 책처럼, 앞으로 만들어질 음식(객체)들이 어떤 맛(기능)을 가질지 미리 정해두는 곳이죠.
이 두 친구가 만나는 특별한 순간이 있어요. new 키워드로 새로운 객체를 만들 때, 그 객체의 __proto__는 자동으로 생성자 함수의 prototype 상자를 가리키게 되어요. 이렇게 해서 객체는 생성자 함수가 준비해둔 모든 기능들을 자연스럽게 사용할 수 있게 되는 거예요.
현실 속 이야기: 작은 도서관의 대출 시스템
__proto__와 prototype을 더 쉽게 이해하기 위해 '우리 동네 작은 도서관' 이야기를 해볼게요.
동네에는 작은 도서관이 하나 있어요. 이 도서관에는 여러 종류의 도서 목록(prototype)이 있어요. 아동 도서 목록, 과학 도서 목록, 소설 목록... 각 목록에는 그 분야의 모든 책들이 정리되어 있어요.
새로운 사람이 도서관 회원이 되면, 도서관에서는 그 사람에게 회원증(__proto__)을 발급해줘요. 이 회원증에는 "내가 어떤 목록을 이용할 수 있는지" 알려주는 정보가 들어있어요.
회원이 어떤 책을 찾으려고 할 때, 먼저 자신의 가방에서 그 책을 가지고 있는지 확인해봐요. 만약 없다면 회원증을 보고 자신이 이용할 수 있는 도서 목록을 찾아가서 "이 책이 있나?"하고 찾아보는 거죠.
이처럼 prototype은 도서 목록이고, __proto__는 "내가 어떤 목록을 이용할 수 있는지"를 알려주는 회원증인 셈이에요.
🎯 __proto__와 prototype을 배우는 이유
이 두 친구를 이해하는 것이 왜 중요할까요? 여러 가지 중요한 이유들이 있어요.
먼저 자바스크립트의 상속 시스템을 완전히 이해할 수 있게 되어요. 다른 프로그래밍 언어와 달리 자바스크립트는 이 두 개념을 통해 객체들이 서로 기능을 공유하는 독특한 방식을 가지고 있어요. 이를 이해하면 자바스크립트가 어떻게 동작하는지 훨씬 깊이 알 수 있어요.
둘째로 메모리를 효율적으로 사용하는 방법을 배울 수 있어요. 같은 기능을 여러 객체가 각각 가지고 있는 대신, prototype에 한 번만 정의해두면 모든 객체가 공유해서 사용할 수 있거든요. 마치 동네 전체가 도서관 한 곳을 공유하는 것처럼 말이에요.
셋째로 기존 객체에 새로운 기능을 추가하는 강력한 방법을 익힐 수 있어요. 이미 만들어진 Array나 String 같은 기본 객체들에도 우리만의 특별한 기능을 추가할 수 있어요.
마지막으로 다른 사람이 만든 코드를 이해하는 데 큰 도움이 되어요. 많은 자바스크립트 라이브러리와 프레임워크들이 이 개념들을 활용해서 만들어졌거든요.
⚙️ 기본 문법 살펴보기
__proto__와 prototype을 사용하는 기본적인 방법들을 알아보겠습니다.
prototype 사용하기:
function 생성자함수() { }
생성자함수.prototype.새로운기능 = function() {
// 기능 내용
};
proto 확인하기:
let 객체 = new 생성자함수();
console.log(객체.__proto__ === 생성자함수.prototype); // true
간단한 예시:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
return this.name + "이(가) 소리를 내요";
};
let dog = new Animal("멍멍이");
console.log(dog.__proto__ === Animal.prototype); // true
console.log(dog.speak()); // "멍멍이이(가) 소리를 내요"
🧪 직접 해보면서 배우기
이제 실제 예제를 통해 이 두 친구가 어떻게 함께 작동하는지 자세히 살펴보겠습니다.
🔹 첫 번째 예시: 기본적인 관계 확인하기
첫 번째 예시에서는 __proto__와 prototype이 어떻게 연결되어 있는지 직접 눈으로 확인해보겠습니다.
// 로봇을 만드는 공장(생성자 함수)을 정의해요
function Robot(name) {
this.name = name; // 로봇의 이름을 설정해요
}
// 로봇 공장의 설계도(prototype)에 기능을 추가해요
Robot.prototype.sayHello = function() {
return "안녕하세요! 저는 " + this.name + " 로봇이에요";
};
// 새로운 로봇을 만들어봅시다
let myRobot = new Robot("AI봇");
// 이제 관계를 확인해볼게요
console.log(myRobot.__proto__ === Robot.prototype); // true - 연결되어 있어요!
// 로봇이 설계도의 기능을 사용할 수 있는지 확인해봅시다
console.log(myRobot.sayHello()); // "안녕하세요! 저는 AI봇 로봇이에요"
// constructor 속성도 확인해봅시다
console.log(myRobot.constructor === Robot); // true - 자신을 만든 생성자를 기억해요
console.log(Robot.prototype.constructor === Robot); // true - prototype도 자신의 생성자를 기억해요
이 과정을 단계별로 살펴보면, 먼저 Robot이라는 생성자 함수를 만들고 각 로봇의 이름을 설정할 수 있게 해요. 그다음 Robot.prototype에 모든 로봇이 공유할 sayHello 기능을 추가하죠. 새로운 로봇을 만들 때 new 키워드가 자동으로 그 로봇의 __proto__를 Robot.prototype에 연결해줘요. 마지막으로 로봇이 자신이 직접 가지지 않은 sayHello 기능을 __proto__를 통해 찾아서 사용하는 것을 확인해요.
🔹 두 번째 예시: 여러 객체가 같은 기능 공유하기
두 번째 예시에서는 여러 객체가 어떻게 같은 prototype을 공유하여 메모리를 절약하고 일관된 기능을 제공하는지 알아보겠습니다.
// 자동차 공장을 만들어봅시다
function Car(brand, color) {
this.brand = brand; // 자동차 브랜드를 설정해요
this.color = color; // 자동차 색깔을 설정해요
}
// 모든 자동차가 공유할 기능들을 설계도에 추가해요
Car.prototype.start = function() {
return this.brand + " 자동차가 부르릉 출발해요!";
};
Car.prototype.getInfo = function() {
return this.color + " 색깔의 " + this.brand + " 자동차예요";
};
// 여러 대의 자동차를 만들어봅시다
let car1 = new Car("현대", "빨강");
let car2 = new Car("기아", "파랑");
let car3 = new Car("BMW", "검정");
// 모든 자동차가 같은 prototype을 공유하는지 확인해봅시다
console.log(car1.__proto__ === car2.__proto__); // true
console.log(car2.__proto__ === car3.__proto__); // true
console.log(car1.__proto__ === Car.prototype); // true
// 각 자동차가 공유 기능을 사용할 수 있는지 확인해봅시다
console.log(car1.start()); // "현대 자동차가 부르릉 출발해요!"
console.log(car2.getInfo()); // "파랑 색깔의 기아 자동차예요"
console.log(car3.start()); // "BMW 자동차가 부르릉 출발해요!"
// 나중에 새로운 기능을 추가해봅시다
Car.prototype.honk = function() {
return this.brand + " 자동차가 빵빵 소리를 내요!";
};
// 이미 만들어진 자동차들도 새 기능을 사용할 수 있어요!
console.log(car1.honk()); // "현대 자동차가 빵빵 소리를 내요!"
console.log(car2.honk()); // "기아 자동차가 빵빵 소리를 내요!"
이 예시를 통해 우리는 여러 중요한 사실을 확인할 수 있어요. 먼저 서로 다른 자동차 객체들이 모두 같은 Car.prototype을 가리키고 있어 메모리를 효율적으로 사용해요. 그다음 각 자동차는 자신만의 고유한 속성(brand, color)을 가지면서도 공통 기능(start, getInfo)은 공유해서 사용하죠. 마지막으로 나중에 Car.prototype에 새로운 기능을 추가하면 이미 만들어진 모든 자동차들도 그 기능을 즉시 사용할 수 있게 되어요.
🔹 세 번째 예시: 프로토타입 체인과 함께 살펴보기
세 번째 예시에서는 프로토타입 체인과 함께 __proto__와 prototype이 어떻게 작동하는지 관찰해보겠습니다.
// 동물의 기본 틀을 만들어봅시다
function Animal(name) {
this.name = name;
}
// 모든 동물이 할 수 있는 기본 행동을 정의해요
Animal.prototype.breathe = function() {
return this.name + "이(가) 깊게 숨을 쉬어요";
};
Animal.prototype.move = function() {
return this.name + "이(가) 신나게 움직여요";
};
// 개라는 더 구체적인 동물을 만들어봅시다
function Dog(name, breed) {
this.name = name;
this.breed = breed; // 견종을 추가해요
}
// 개는 동물의 특징을 물려받아요 (간단한 방법)
Dog.prototype = Animal.prototype;
// 개만의 특별한 행동을 추가해요
Dog.prototype.bark = function() {
return this.name + "이(가) 멍멍 짖어요";
};
// 새로운 개를 만들어봅시다
let myDog = new Dog("뽀삐", "치와와");
// 개가 여러 단계의 프로토타입 체인을 따라 기능을 찾는지 확인해봅시다
console.log(myDog.bark()); // "뽀삐이(가) 멍멍 짖어요" (Dog.prototype에서 찾았어요)
console.log(myDog.breathe()); // "뽀삐이(가) 깊게 숨을 쉬어요" (Animal.prototype에서 찾았어요)
console.log(myDog.move()); // "뽀삐이(가) 신나게 움직여요" (Animal.prototype에서 찾았어요)
// 프로토타입 체인을 확인해보기
console.log(myDog.__proto__ === Dog.prototype); // true
console.log(Dog.prototype === Animal.prototype); // true (간단하게 연결했어요)
// 생성자 정보 확인하기
console.log(myDog.constructor === Dog); // false - Animal을 가리키게 되었어요
console.log(myDog.constructor === Animal); // true
이 예시에서는 간단한 프로토타입 연결 방법을 사용했어요. 하지만 이렇게 하면 constructor 속성에 문제가 생긴다는 것을 확인할 수 있어요. 나중에 더 안전한 방법을 배우게 될 거예요.
🔄 __proto__와 prototype 사용 과정 정리
지금까지 학습한 두 친구의 사용 과정을 자연스럽게 정리해보겠습니다.
첫 번째 단계는 생성자 함수 정의와 prototype 설정이에요. function 생성자함수() { } 형태로 객체를 만들 틀을 준비하고, 생성자함수.prototype에 모든 인스턴스가 공유할 기능들을 정의하는 것이죠.
두 번째는 객체 생성과 자동 연결 단계예요. new 생성자함수() 형태로 새 객체를 만들면, 그 객체의 __proto__가 자동으로 생성자함수.prototype을 가리키게 되어요. 이는 자바스크립트 엔진이 자동으로 해주는 일이에요.
세 번째는 기능 사용과 프로토타입 체인 탐색 단계예요. 객체가 어떤 기능을 호출할 때, 먼저 자신이 직접 그 기능을 가지고 있는지 확인하고, 없으면 __proto__를 따라 프로토타입에서 찾아보는 과정이 일어나요.
마지막으로 가장 중요한 것은 일관성 있는 사용이에요. __proto__는 모든 객체가 가지고 있고, prototype은 생성자 함수만 가지고 있다는 것을 항상 기억해야 해요.
🧚♀️ 이야기로 다시 배우기: 도서관의 대출 시스템
지금까지 배운 내용을 하나의 따뜻한 이야기로 다시 정리해볼까요?
어느 작은 마을에는 정말 특별한 도서관이 있었어요. 이 도서관에는 아주 독특한 대출 시스템이 있었답니다.
도서관에는 여러 분야별로 책 목록(prototype)이 있었어요. 각 목록에는 그 분야의 모든 책들이 정리되어 있었죠. 예를 들어, 요리 목록에는 모든 요리 레시피 책이, 과학 목록에는 모든 과학 도서가 담겨 있었어요.
새로운 주민이 도서관 회원이 되면, 사서 선생님께서는 그 사람에게 특별한 회원증(__proto__)을 발급해주세요. 이 회원증에는 "내가 어떤 분야의 책 목록을 이용할 수 있는지" 알려주는 정보가 들어있어요.
어떤 주민이 책을 찾으려고 할 때, 먼저 자신의 개인 서재(객체 자신의 속성)에서 그 책을 가지고 있는지 확인해봐요. 만약 없다면 회원증을 확인해서 자신이 이용할 수 있는 도서관의 책 목록을 찾아가서 "이 책이 있나?"하고 찾아보는 거예요.
만약 그 목록에도 없다면, 더 큰 범위의 목록을 찾아보게 되죠. 이렇게 도서관 전체의 목록 체계를 차례대로 찾아보면서 결국 필요한 책을 찾게 되어요.
이처럼 prototype은 도서관의 책 목록이고, __proto__는 자신의 목록을 찾아주는 회원증인 셈이에요. 두 친구가 함께 일해서 모든 주민들이 필요한 책을 효율적으로 찾을 수 있게 도와주는 거예요.
🧠 자주 하는 실수와 주의할 점
__proto__와 prototype을 사용할 때 자주 하는 실수들을 미리 알아두면 더 안전한 코딩을 할 수 있어요.
❌ 실수 1: 일반 객체에 prototype 속성이 있다고 생각하기
let myObject = { name: "철수" };
// 잘못된 생각: 일반 객체도 prototype을 가지고 있다
console.log(myObject.prototype); // undefined - 일반 객체는 prototype 속성이 없어요!
// 올바른 방법: __proto__는 모든 객체가 가지고 있어요
console.log(myObject.__proto__); // Object.prototype을 가리켜요
// 함수만 prototype 속성을 가져요
function MyFunction() {}
console.log(MyFunction.prototype); // 함수의 prototype 객체가 출력되어요
이런 실수가 발생하는 이유는 prototype 속성이 함수 객체에만 존재하기 때문이에요. 일반 객체인 myObject는 prototype 속성을 가지지 않아서 undefined가 나와요. prototype은 생성자 함수가 "내가 만들어낼 객체들이 사용할 기능들"을 모아두는 특별한 상자이므로, 일반 객체가 가질 이유가 없어요.
❌ 실수 2: proto와 prototype을 헷갈려서 사용하기
function Dog(name) {
this.name = name;
}
let myDog = new Dog("뽀삐");
// 헷갈리기 쉬운 부분들
console.log(myDog.prototype); // undefined - 인스턴스는 prototype 속성이 없어요
console.log(myDog.__proto__); // Dog.prototype을 가리켜요
console.log(Dog.prototype); // Dog 함수의 prototype 객체예요
console.log(Dog.__proto__); // Function.prototype을 가리켜요 (함수도 객체예요)
// 기능 추가할 때 올바른 방법
Dog.prototype.sit = function() {
return this.name + "이(가) 앉았어요";
};
console.log(myDog.sit()); // "뽀삐이(가) 앉았어요"
myDog.__proto__와 Dog.prototype은 같은 곳을 가리키지만, 의미상으로는 다르다는 것을 이해해야 해요. myDog.__proto__는 "내 프로토타입이 뭐지?"를 나타내고, Dog.prototype은 "Dog로 만든 객체들이 사용할 기능들이 담긴 상자"를 나타내요.
❌ 실수 3: constructor 속성을 무시하기
function Animal() {}
Animal.prototype.move = function() { return "움직여요"; };
function Dog() {}
Dog.prototype = Animal.prototype; // 간단하지만 문제가 있는 방법
let myDog = new Dog();
// 문제 발생: constructor가 엉뚱한 곳을 가리켜요
console.log(myDog.constructor === Dog); // false
console.log(myDog.constructor === Animal); // true - 이상하죠?
// 해결 방법: constructor를 수동으로 복구해요
Dog.prototype.constructor = Dog;
console.log(myDog.constructor === Dog); // 이제 true가 되어요
prototype을 직접 할당할 때는 constructor 속성도 함께 고려해야 해요. 그렇지 않으면 객체가 자신을 만든 생성자를 잘못 기억하게 되어 나중에 문제가 될 수 있어요.
✏️ 직접 해보기를 시작하기 전에
이제 여러분이 직접 __proto__와 prototype을 다뤄볼 시간이에요. 처음에는 어렵게 느껴질 수 있어요. 마치 새로운 악기를 배우는 것처럼 손가락이 어색하고 소리가 제대로 나지 않을 수도 있어요.
하지만 차근차근 연습하다 보면 점점 익숙해질 거예요. 두 친구의 차이점을 명확히 이해하고, 언제 어떤 것을 사용해야 하는지 자연스럽게 알게 될 거예요. 천천히 따라해보세요.
Ex1) 생성자 함수를 만들고 __proto__와 prototype의 관계를 확인해보자
// 학생을 만드는 생성자 함수를 정의해보세요
function Student(name, grade) {
this.name = name; // 학생의 이름을 저장해요
this.grade = grade; // 학생의 학년을 저장해요
}
// 모든 학생이 공유할 기능을 prototype에 추가해보세요
Student.prototype.study = function() {
return this.name + "이(가) 열심히 공부해요";
};
Student.prototype.introduce = function() {
return "안녕하세요, " + this.grade + "학년 " + this.name + "이에요";
};
// 새로운 학생 객체를 만들어보세요
let student1 = new Student("지민", 5);
// __proto__와 prototype의 관계를 확인해보세요
console.log(student1.__proto__ === Student.prototype); // true - 연결되어 있어요!
console.log(student1.constructor === Student); // true - 생성자도 올바르게 연결되어 있어요
console.log(Student.prototype.constructor === Student); // true
// 기능 사용해보기
console.log(student1.study()); // "지민이(가) 열심히 공부해요"
console.log(student1.introduce()); // "안녕하세요, 5학년 지민이에요"
Ex2) 여러 객체가 같은 prototype을 공유하는지 확인해보자
// 과일을 만드는 생성자 함수
function Fruit(name, color) {
this.name = name; // 과일의 이름을 저장해요
this.color = color; // 과일의 색깔을 저장해요
}
// 모든 과일이 공유할 기능을 추가해요
Fruit.prototype.describe = function() {
return this.color + " 색깔의 맛있는 " + this.name + "이에요";
};
// 여러 과일 객체를 생성해요
let apple = new Fruit("사과", "빨강");
let banana = new Fruit("바나나", "노랑");
let grape = new Fruit("포도", "보라");
// 모든 객체가 같은 prototype을 공유하는지 확인해요
console.log(apple.__proto__ === banana.__proto__); // true
console.log(banana.__proto__ === grape.__proto__); // true
console.log(apple.__proto__ === Fruit.prototype); // true
// 모든 객체가 같은 기능을 사용할 수 있는지 확인해요
console.log(apple.describe()); // "빨강 색깔의 맛있는 사과이에요"
console.log(banana.describe()); // "노랑 색깔의 맛있는 바나나이에요"
// 나중에 새 기능을 추가하면 모든 과일이 사용할 수 있어요
Fruit.prototype.eat = function() {
return "냠냠! " + this.name + "을(를) 맛있게 먹어요";
};
console.log(apple.eat()); // "냠냠! 사과을(를) 맛있게 먹어요"
console.log(grape.eat()); // "냠냠! 포도을(를) 맛있게 먹어요"
Ex3) prototype 속성과 __proto__ 속성의 차이점 확인하기
// 함수와 일반 객체 준비하기
function MyFunction() {
this.value = "함수로 만든 객체";
}
let myObject = { value: "일반 객체" };
let myInstance = new MyFunction();
// prototype 속성 확인하기
console.log("=== prototype 속성 확인 ===");
console.log("MyFunction.prototype:", typeof MyFunction.prototype); // "object" - 함수는 prototype을 가져요
console.log("myObject.prototype:", myObject.prototype); // undefined - 일반 객체는 prototype이 없어요
console.log("myInstance.prototype:", myInstance.prototype); // undefined - 인스턴스도 prototype이 없어요
// __proto__ 속성 확인하기
console.log("\n=== __proto__ 속성 확인 ===");
console.log("MyFunction.__proto__:", typeof MyFunction.__proto__); // "object" - 함수도 객체이므로 __proto__를 가져요
console.log("myObject.__proto__:", typeof myObject.__proto__); // "object" - 모든 객체는 __proto__를 가져요
console.log("myInstance.__proto__:", typeof myInstance.__proto__); // "object" - 인스턴스도 __proto__를 가져요
// 연결 관계 확인하기
console.log("\n=== 연결 관계 확인 ===");
console.log("myInstance.__proto__ === MyFunction.prototype:",
myInstance.__proto__ === MyFunction.prototype); // true
🤔 조금 더 어려운 문제로 실력 확인하기
기본 연습을 마쳤다면, 이제 조금 더 깊이 있는 문제들을 통해 이해도를 확인해보겠습니다.
Q1. 아래 코드를 실행했을 때 각 console.log의 출력 결과를 예측하고, 그 이유를 설명해보세요.
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
return "제 이름은 " + this.name + "이에요";
};
let person1 = new Person("민수");
let person2 = new Person("영희");
console.log(person1.sayName()); // ?
console.log(person1.__proto__ === person2.__proto__); // ?
console.log(Person.prototype.constructor === Person); // ?
console.log(person1.constructor === Person); // ?
정답 및 해설:
person1.sayName()은"제 이름은 민수이에요"를 출력해요. person1 객체 자체에는 sayName 기능이 없지만,__proto__를 통해Person.prototype에서 찾아서 실행하기 때문이에요.person1.__proto__ === person2.__proto__는true예요. 두 객체 모두 같은 생성자 함수Person으로 만들어졌으므로, 같은Person.prototype을 가리키고 있어요.Person.prototype.constructor === Person은true예요. 모든 함수의 prototype 객체는 자동으로 그 함수를 가리키는 constructor 속성을 가지게 되거든요.person1.constructor === Person도true예요. person1이 직접 constructor 속성을 가지지 않아서 프로토타입 체인을 통해Person.prototype.constructor를 찾아서 사용하기 때문이에요.
Q2. 다음 코드에서 프로토타입 관계를 설명해보세요.
function Animal() {}
Animal.prototype.move = function() { return "움직여요"; };
function Bird() {}
Bird.prototype = Animal.prototype;
let sparrow = new Bird();
console.log(sparrow.move()); // ?
console.log(sparrow.constructor === Bird); // ?
console.log(sparrow.constructor === Animal); // ?
정답 및 해설:
sparrow.move()는"움직여요"를 출력해요. sparrow의__proto__가Bird.prototype을 가리키고,Bird.prototype이Animal.prototype과 같으므로Animal.prototype.move를 찾아서 실행해요.sparrow.constructor === Bird는false예요.Bird.prototype = Animal.prototype으로 할당했기 때문에 constructor 속성이 Animal을 가리키게 되었어요.sparrow.constructor === Animal은true예요. 위와 같은 이유로 constructor가 Animal을 가리키고 있어요.
이것이 간단한 프로토타입 연결 방법의 문제점이에요. 나중에 더 안전한 방법을 배우게 될 거예요!
📚 복습 문제 - 이전에 배운 내용 기억하기
이제 이전 단원에서 배운 중요한 내용들을 복습해보며 기억을 새롭게 해볼게요!
🔄 복습 1: 프로토타입 체인 기본 개념 (16.1.2 단원 복습)
// 문제: 다음 코드에서 빈 칸을 채워 프로토타입 체인을 완성해보세요.
// 동물 생성자 함수
function Animal(name) {
this.name = name;
}
Animal.prototype.breathe = function() {
return `${this.name}이(가) 숨을 쉬어요.`;
};
// 강아지 생성자 함수
function Dog(name, breed) {
this.name = name;
this.breed = breed;
}
// 간단한 프로토타입 체인 설정
Dog.______ = Animal.______; // 빈 칸 1, 2: 프로토타입 연결
Dog.prototype.bark = function() {
return `${this.name}: 멍멍!`;
};
// 강아지 객체 생성
let myDog = new Dog("바둑이", "진돗개");
// 체인 관계 확인 - 빈 칸을 채워주세요!
console.log(myDog.______ === Dog.prototype); // 빈 칸 3: 프로토타입 연결 속성
console.log(myDog ______ Dog); // 빈 칸 4: 인스턴스 확인 연산자
console.log(myDog ______ Animal); // 빈 칸 5: 체인 상위 확인
정답:
Dog.prototype = Animal.prototype; // 빈 칸 1, 2: prototype
console.log(myDog.__proto__ === Dog.prototype); // 빈 칸 3: __proto__
console.log(myDog instanceof Dog); // 빈 칸 4: instanceof
console.log(myDog instanceof Animal); // 빈 칸 5: instanceof
해설: 간단한 프로토타입 연결은 Dog.prototype = Animal.prototype으로 할 수 있고, __proto__는 객체의 프로토타입을 가리키며, instanceof는 객체가 특정 생성자의 인스턴스인지 확인하는 연산자입니다.
🔄 복습 2: 프로토타입 체인 검색 과정 (16.1.2 단원 복습)
// 문제: 다음 코드의 실행 결과를 예측해보세요.
function Grandparent() {
this.generation = "할아버지";
}
Grandparent.prototype.wisdom = function() {
return "할아버지의 지혜";
};
function Parent() {
this.generation = "아버지";
}
Parent.prototype = Grandparent.prototype; // 간단한 연결
Parent.prototype.experience = function() {
return "아버지의 경험";
};
function Child() {
this.generation = "자식";
}
Child.prototype = Parent.prototype; // 간단한 연결
Child.prototype.energy = function() {
return "자식의 에너지";
};
let child = new Child();
console.log(child.generation); // 결과 1: ?
console.log(child.energy()); // 결과 2: ?
console.log(child.experience()); // 결과 3: ?
console.log(child.wisdom()); // 결과 4: ?
정답:
자식
자식의 에너지
아버지의 경험
할아버지의 지혜해설:
child.generation은 객체 자신의 속성에서 찾아서 "자식"이 출력됩니다.- 나머지 기능들은 모두 프로토타입에서 찾아서 사용하는데, 간단한 연결 방법을 사용했기 때문에 모든 기능이 같은 프로토타입 객체에 들어있어서 모두 접근할 수 있습니다.
지금까지 __proto__와 prototype의 모든 비밀을 함께 알아보았어요. 이 두 친구의 차이점과 협력 방식을 이해하면 자바스크립트의 상속 시스템을 완전히 마스터할 수 있어요!
✅ 학습 완료 체크리스트
이번 시간에 배운 내용들을 모두 이해했는지 확인해보세요!
| 학습 내용 | 이해했나요? |
|---|---|
| proto와 prototype의 차이점 | ✅ |
| 두 속성의 각각의 역할과 특징 | ✅ |
| 객체 생성 시 자동 연결 과정 | ✅ |
| constructor 속성의 의미 | ✅ |
| 실전 예제 이해 | ✅ |
📂 마무리 정보
오늘 배운 16.1.3 내용이 여러분의 자바스크립트 지식 상자에 잘 저장되었나요? 다음 시간에는 더 재미있는 내용으로 만나요!
기억할 점: __proto__는 모든 객체가 가지는 프로토타입 연결선이고, prototype은 생성자 함수만 가지는 설계도 상자예요. 마치 도서관에서 책을 찾는 회원증과 책 목록의 차이처럼 말이에요!
무료 JavaScript 학습 플랫폼에서 단계별 학습과 실시간 코드 실행을 통해
더욱 효과적이고 재미있게 학습하실 수 있습니다.
'16. 프로토타입과 상속의 비밀 > 16.1 prototype 개념' 카테고리의 다른 글
| 16.1.2 프로토타입 체인 - 가족처럼 이어진 특별한 연결고리 (0) | 2025.07.23 |
|---|---|
| 16.1.1 프로토타입이라는 특별한 시스템 - 자바스크립트의 독특한 가족 연결 방식 (0) | 2025.07.23 |