프로토타입의 정의
- 자바스크립트는 프로토타입 기반 언어이다. 프로토타입 객체를 통해 객체의 메서드와 속성들을 상속한다.
- 자바스크립트에서는 객체를 생성할 때 자신의 부모 객체와 연결되는 링크를 가지게 된다.
프로토타입의 이해
프로토타입을 알아보기 위해 간단한 Person 생성자를 만들어보겠습니다.
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function () {
console.log("HI");
};
}
console.dir(Person); // 1
const person1 = new Person("heeji", 100);
console.dir(person1); // 2
1의 결과

2의 결과

생성된 person1 인스턴스를 보면 name, age, sayHi가 우리가 정의한대로 생성된 것을 볼 수 있습니다. new 키워드를 생성자 함수 앞에 붙여 인스턴스를 생성하고 (이 때 this는 인스턴스가 된다) 그곳에 속성과 메서드들을 넣어준 것입니다.
콘솔에 찍힌 prototype
과 [[Prototype]]
이 눈에 띕니다. 콘솔에서 아무리해도 person1의 [[Prototype]]
에 접근할 수가 없네요. 검색해봅니다. [[Prototype]]
의 getter이자 setter인 __proto__
라는 것이 존재함을 찾을 수 있었습니다.
console.dir(Person.prototype);
console.dir(person1.__proto__);
console.log(Person.prototype === person1.__proto__);
실행 결과

콘솔에 찍어보면 생성자 함수의 prototype
과 인스턴스의 __proto__
가 동일한 값임을 알 수 있습니다.
생성자 함수로 인스턴스를 생성하면 생성자함수의 prototype
이 인스턴스의 [[Prototype]]
으로 추가됩니다.
prototype 객체가 있고 이것이 인스턴스의 프로토타입이 된다는 것을 확인했습니다. 좀 더 알아보기 위해 sayHi 함수를 Person의 prototype에 바로 적용해볼까요
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("HI");
};
const person1 = new Person("heeji", 100);
console.dir(Person.prototype);
console.dir(person1.__proto__);

Person의 prototype
과 person1의 __proto__
는 동일한 객체임을 확인할 수 있습니다.
새로운 인스턴스를 생성하기 전에 prototype에 메서드를 추가했기 때문에 가능한 걸까요?
한 번 순서를 바꿔보겠습니다.
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person("heeji", 100);
console.dir("1", person1.__proto__);
Person.prototype.sayHi = function () {
console.log("HI");
};
person1.sayHi();
console.dir("2", Person.prototype);
console.dir("3", person1.__proto__);

- 인스턴스 생성 이후에 Person의 prototype에 sayHi 메서드를 정의해도 무사히 sayHi를 사용할 수 있음을 확인했습니다. 이를 통해 우리는__proto__
는 prototype
을 참조하는 값임을 알 수 있습니다. 생성자를 변경했음에도 그 내용이 인스턴스에 반영되니까요
이 것을 통해 우리는 응용법을 생각할 수 있습니다. 앞의 예제를 다시 봅시다.
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function () {
console.log("HI");
};
}
const person1 = new Person("heeji", 20);
const person2 = new Person("huge", 100);
console.dir(person1);
console.dir(person2);
해당 생성자로 인스턴스를 만들면

인스턴스마다 sayHi 함수가 객체의 프로퍼티로 존재하는 것을 확인할 수 있습니다. 이렇게 되면 인스턴스가 많아질 때 불필요하게 메모리를 사용하게 되는 문제가 생기겠죠. 앞에서 sayHi 메서드를 생성자의 prototype
에 정의하고 사용하는 예제를 봤습니다. 이렇게 하면 인스턴스 객체의 프로퍼티에 메서드가 정의되는 것이 아니라 프로토타입을 참조해 해당 메서드를 호출할 수 있습니다.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("HI");
};
const person1 = new Person("heeji", 20);
const person2 = new Person("huge", 100);
console.dir(person1);
console.dir(person2);

콘솔을 보면 각 인스턴스에 sayHi 프로퍼티가 없는 것을 확인할 수 있습니다. 이렇게 되면 메모리를 아낄 수 있겠네요.
그런데 이상합니다. person1에 sayHi라는 프로퍼티가 없는데 어떻게 person1.sayHi()
를 호출할 수 있는 걸까요? 이는 프로토타입 체이닝 덕분입니다.
자바스크립트는 person1.sayHi() 구문을 보고 먼저 person1이 해당 프로퍼티를 가지고 있는지 확인합니다. 만약 없다면 person1의 __proto__
에서 해당 프로퍼티를 찾습니다. 이곳에서 찾으면 그것을 사용하게 됩니다. 만약 이곳에 또 없다면 __proto__
의 __proto__
를 찾아봅니다. 이런 식으로 프로토타입이 줄줄이 엮여있는 것을 프로토타입 체인이라고 하고 속성을 찾아다니는 것을 프로토타입 체이닝이라고 합니다. __proto__
가 null이 될 때까지 프로토타입 체이닝이 일어납니다.
클래스
앞에서 메모리 효율을 위해 메서드를 prototype에 정의해보았는데요. ES6에 추가된 클래스는 이것을 사용하기 쉽게 해줍니다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHi() {
console.log("HI");
}
}
const person1 = new Person("heeji", 20);
console.dir(person1);
person1.sayHi();

person1의 프로퍼티에 sayHi가 추가되는 것이 아니라 프로토타입에 sayHi가 정의되어있는 것을 확인할 수 있습니다.
참고자료
'공부기록 > JavaScript' 카테고리의 다른 글
스코프와 스코프체인 (0) | 2024.03.22 |
---|---|
클로저에 대해 (0) | 2024.03.22 |
일급함수 & 콜백함수, 고차함수 (0) | 2024.03.22 |
이벤트 루프란? (0) | 2024.03.22 |
자바스크립트에서 비동기 프로그래밍 (0) | 2024.03.22 |
프로토타입의 정의
- 자바스크립트는 프로토타입 기반 언어이다. 프로토타입 객체를 통해 객체의 메서드와 속성들을 상속한다.
- 자바스크립트에서는 객체를 생성할 때 자신의 부모 객체와 연결되는 링크를 가지게 된다.
프로토타입의 이해
프로토타입을 알아보기 위해 간단한 Person 생성자를 만들어보겠습니다.
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function () {
console.log("HI");
};
}
console.dir(Person); // 1
const person1 = new Person("heeji", 100);
console.dir(person1); // 2
1의 결과

2의 결과

생성된 person1 인스턴스를 보면 name, age, sayHi가 우리가 정의한대로 생성된 것을 볼 수 있습니다. new 키워드를 생성자 함수 앞에 붙여 인스턴스를 생성하고 (이 때 this는 인스턴스가 된다) 그곳에 속성과 메서드들을 넣어준 것입니다.
콘솔에 찍힌 prototype
과 [[Prototype]]
이 눈에 띕니다. 콘솔에서 아무리해도 person1의 [[Prototype]]
에 접근할 수가 없네요. 검색해봅니다. [[Prototype]]
의 getter이자 setter인 __proto__
라는 것이 존재함을 찾을 수 있었습니다.
console.dir(Person.prototype);
console.dir(person1.__proto__);
console.log(Person.prototype === person1.__proto__);
실행 결과

콘솔에 찍어보면 생성자 함수의 prototype
과 인스턴스의 __proto__
가 동일한 값임을 알 수 있습니다.
생성자 함수로 인스턴스를 생성하면 생성자함수의 prototype
이 인스턴스의 [[Prototype]]
으로 추가됩니다.
prototype 객체가 있고 이것이 인스턴스의 프로토타입이 된다는 것을 확인했습니다. 좀 더 알아보기 위해 sayHi 함수를 Person의 prototype에 바로 적용해볼까요
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("HI");
};
const person1 = new Person("heeji", 100);
console.dir(Person.prototype);
console.dir(person1.__proto__);

Person의 prototype
과 person1의 __proto__
는 동일한 객체임을 확인할 수 있습니다.
새로운 인스턴스를 생성하기 전에 prototype에 메서드를 추가했기 때문에 가능한 걸까요?
한 번 순서를 바꿔보겠습니다.
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person("heeji", 100);
console.dir("1", person1.__proto__);
Person.prototype.sayHi = function () {
console.log("HI");
};
person1.sayHi();
console.dir("2", Person.prototype);
console.dir("3", person1.__proto__);

- 인스턴스 생성 이후에 Person의 prototype에 sayHi 메서드를 정의해도 무사히 sayHi를 사용할 수 있음을 확인했습니다. 이를 통해 우리는__proto__
는 prototype
을 참조하는 값임을 알 수 있습니다. 생성자를 변경했음에도 그 내용이 인스턴스에 반영되니까요
이 것을 통해 우리는 응용법을 생각할 수 있습니다. 앞의 예제를 다시 봅시다.
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function () {
console.log("HI");
};
}
const person1 = new Person("heeji", 20);
const person2 = new Person("huge", 100);
console.dir(person1);
console.dir(person2);
해당 생성자로 인스턴스를 만들면

인스턴스마다 sayHi 함수가 객체의 프로퍼티로 존재하는 것을 확인할 수 있습니다. 이렇게 되면 인스턴스가 많아질 때 불필요하게 메모리를 사용하게 되는 문제가 생기겠죠. 앞에서 sayHi 메서드를 생성자의 prototype
에 정의하고 사용하는 예제를 봤습니다. 이렇게 하면 인스턴스 객체의 프로퍼티에 메서드가 정의되는 것이 아니라 프로토타입을 참조해 해당 메서드를 호출할 수 있습니다.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("HI");
};
const person1 = new Person("heeji", 20);
const person2 = new Person("huge", 100);
console.dir(person1);
console.dir(person2);

콘솔을 보면 각 인스턴스에 sayHi 프로퍼티가 없는 것을 확인할 수 있습니다. 이렇게 되면 메모리를 아낄 수 있겠네요.
그런데 이상합니다. person1에 sayHi라는 프로퍼티가 없는데 어떻게 person1.sayHi()
를 호출할 수 있는 걸까요? 이는 프로토타입 체이닝 덕분입니다.
자바스크립트는 person1.sayHi() 구문을 보고 먼저 person1이 해당 프로퍼티를 가지고 있는지 확인합니다. 만약 없다면 person1의 __proto__
에서 해당 프로퍼티를 찾습니다. 이곳에서 찾으면 그것을 사용하게 됩니다. 만약 이곳에 또 없다면 __proto__
의 __proto__
를 찾아봅니다. 이런 식으로 프로토타입이 줄줄이 엮여있는 것을 프로토타입 체인이라고 하고 속성을 찾아다니는 것을 프로토타입 체이닝이라고 합니다. __proto__
가 null이 될 때까지 프로토타입 체이닝이 일어납니다.
클래스
앞에서 메모리 효율을 위해 메서드를 prototype에 정의해보았는데요. ES6에 추가된 클래스는 이것을 사용하기 쉽게 해줍니다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHi() {
console.log("HI");
}
}
const person1 = new Person("heeji", 20);
console.dir(person1);
person1.sayHi();

person1의 프로퍼티에 sayHi가 추가되는 것이 아니라 프로토타입에 sayHi가 정의되어있는 것을 확인할 수 있습니다.
참고자료
'공부기록 > JavaScript' 카테고리의 다른 글
스코프와 스코프체인 (0) | 2024.03.22 |
---|---|
클로저에 대해 (0) | 2024.03.22 |
일급함수 & 콜백함수, 고차함수 (0) | 2024.03.22 |
이벤트 루프란? (0) | 2024.03.22 |
자바스크립트에서 비동기 프로그래밍 (0) | 2024.03.22 |