자바스크립트는 명령형, 함수형, 프로토타입 기반, 객체지향 프로그래밍을 모두 지원하는 멀티 패러다임 언어입니다. 흔히 클래스 기반 언어인 Java나 C++과 비교하여 자바스크립트는 객체지향 언어가 아니라고 오해받는 경우가 있지만, 실제로 자바스크립트는 프로토타입 기반 객체지향 언어로, 클래스 없이도 상속과 코드 재사용이 가능합니다.
// 생성자 함수
function Circle(radius) {
this.radius = radius;
this.getArea = function () {
// Math.PI는 원주율을 나타내는 상수
return Math.PI * this.radius ** 2;
};
}
// 반지름이 1인 인스턴스 생성
const c1 = new Circle(1);
// 반지름이 2인 인스턴스 생성
const c2 = new Circle(2);
// Circle 생성자 함수는 인스턴스를 생성할 때마다 동일한 동작을 하는
// getArea() 메서드를 새로 생성하고 모든 인스턴스가 중복 소유한다.
// getArea() 메소드는 하나만 생성하여 모든 인스턴스가 공유해서 사용하는 것이 바람직하다.
console.log(c1.getArea === c2.getArea); // false
getArea() 메서드는 모든 인스턴스에서 동일한 로직을 수행하지만,
각 인스턴스마다 별도의 함수로 생성되어 메모리를 낭비하게 됩니다.
function Circle(radius) {
this.radius = radius;
}
Circle.prototype.getArea = function () {
return Math.PI * this.radius * this.radius;
};
// 프로토타입은 Circle 생성자 함수의 prototype 프로퍼티에 바인딩되어 있습니다.
// 반지름이 1인 인스턴스 생성
const c1 = new Circle(1);
// 반지름이 2인 인스턴스 생성
const c2 = new Circle(2);
Circle 생성자 함수가 생성한 모든 인스턴스는 자신의 프로토타입, 즉 상위 객체 역할을 하는 Circle.prototype의 모든 프로퍼티와 메서드를 상속받습니다.
getArea 메서드는 단 하나만 생성되어 프로토타입인 Circle.prototype의 메서드에 할당되어 있습니다. 따라서 Circle 생성자 함수가 생성하는 모든 인스턴스는 getArea 메서드를 상속받아 사용할 수 있습니다.
인스턴스에서 어떤 프로퍼티나 메서드에 접근할 때, 자바스크립트는 다음과 같은 순서로 값을 찾습니다.
__proto__ (또는 내부 [[Prototype]])로 연결된 프로토타입 객체에서 탐색Object.prototype까지 가서도 없으면 undefined를 반환합니다이런 구조 덕분에, 각 인스턴스는 자신의 상태(state)는 따로 관리하고,
공통 기능은 공유하여 사용할 수 있습니다.
모든 객체는 __proto__ 접근자 프로터티를 통해 자신의 프로토타입, 즉 [[prototype]] 내부 슬롯에 간접적으로 접근할 수 있습니다.

자바스크립트에서 모든 프로토타입 객체는 constructor라는 프로퍼티를 갖고 있습니다.
이 constructor는 말 그대로 "나를 만들어준 생성자 함수가 무엇이었는지"를 가리키는 역할을 합니다.
즉, 프로토타입은 자신을 참조하고 있는 생성자 함수를 기억하고 있습니다.
function Person(name) {
this.name = name;
}
const me = new Person("Lee Hunjin");
// me 객체의 생성자 함수는 Person이다.
console.log(me.constructor === Person) // true
위 코드에서 me는 Person이라는 생성자 함수를 통해 만들어진 객체입니다.
그런데 me 객체 자체에는 constructor라는 프로퍼티가 직접 정의되어 있지 않습니다.
그럼에도 불구하고 me.constructor를 호출할 수 있는 이유는,
me의 내부에는 [[Prototype]]이라는 숨겨진 링크(= proto)가 존재하고,
이 링크는 Person.prototype을 가리키고 있기 때문입니다.
me → Person.prototype → constructor → Person 함수
따라서 me.constructor를 호출하면 결국 Person.prototype.constructor를 참조하게 되고,
그 값은 Person 함수 자체가 되어 true가 출력되는 것입니다.
앞서 살펴본 것처럼, 자바스크립트에서 어떤 객체가 생성되면 해당 객체는 자신을 만들어낸 생성자 함수와 연결됩니다. 이 연결은 객체의 프로토타입에 있는 constructor 프로퍼티를 통해 이루어지며, 이 프로퍼티는 "나를 만든 함수가 누구인지"를 가리킵니다.
// obj 객체를 생성한 생성자 함수는 Object()입니다.
const obj = new Object();
console.log(obj.constructor === Object); // true
여기서 obj.constructor는 Object를 가리킵니다.
즉, obj는 Object 생성자 함수를 통해 만들어졌음을 알 수 있습니다.
// add 함수 객체를 생성한 생성자 함수는 Function()입니다.
const add = function (a, b) {
return a + b;
};
console.log(add.constructor === Function); // true
add는 함수입니다. 그런데 자바스크립트에서는 함수도 객체이기 때문에, 이 함수 역시 어떤 생성자 함수로부터 만들어졌습니다. 그 생성자 함수가 바로 Function()입니다.
// 사용자 정의 생성자 함수
function Person(name) {
this.name = name;
}
// Person 생성자를 통해 me라는 인스턴스를 생성
const me = new Person("훈진");
console.log(me.constructor === Person); // true
위 예제에서는 Person이라는 생성자 함수를 만들어 직접 인스턴스를 생성했습니다.
me 객체는 Person 생성자 함수를 통해 만들어졌고, me.constructor는 바로 그 Person을 가리킵니다.
객체 → 프로토타입 → constructor → 생성자 함수 로 이어지는 구조입니다.// 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 생성
console.log(Person.prototype); // { constructor: ƒ Person(name) }
// 생성자 함수
function Person(name) {
this.name = name;
}
프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성됩니다. 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재합니다.
// 화살표 함수는 non-constructor이므로 생성자 함수로 사용할 수 없다.
const Person = (name) => {
this.name = name;
};
console.log(Person.prototype); // undefined
prototype도 undefined다.this도 바인딩 안 된다. 그래서 객체 만들 목적이면 일반 함수 써야 한다.자바스크립트는 클래스 기반 언어가 아니라 프로토타입 기반 언어입니다.
즉, 객체 간의 상속이 클래스가 아니라 객체에서 객체로 연결되며 이루어집니다.
이 연결 구조를 프로토타입 체인이라고 부릅니다.
function Person(name) {
this.name = name;
}
// 프로토타입 메서드 추가
Person.prototype.sayHello = function() {
console.log(`안녕하세요, ${this.name}입니다.`);
};
const me = new Person('훈진');
console.log(me.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null
여기서 me는 Person 생성자 함수를 통해 만들어진 객체입니다.
즉, me의 내부 [[Prototype]](= proto)은 Person.prototype을 참조합니다.
me → Person.prototype → Object.prototype → null
me는 자신이 가진 프로퍼티(name)를 직접 가지고 있음 → hasOwnProperty('name') → true
me.sayHello()를 호출하면?
me 객체에 sayHello가 없으니,me.__proto__ → Person.prototype에서 찾음 → ✅ 있음me.hasOwnProperty()는?
me에 없음 → Person.prototype에도 없음 → Object.prototype에서 찾음 → ✅ 있음이처럼 필요한 속성이나 메서드를 계속 위로 올라가며 찾는 구조가 바로 프로토타입 체인입니다.