JavaScript

웹 개발의 필수 언어

동적인 웹 페이지 구현을 위한 핵심 프로그래밍 언어.

Java

객체지향 프로그래밍

안정적이고 확장성 있는 백엔드 개발의 대표 언어.

HTML

웹의 기초

웹 페이지의 구조를 정의하는 마크업 언어.

React

현대적 UI 라이브러리

효율적인 사용자 인터페이스 구축을 위한 JavaScript 라이브러리.

CSS

웹 디자인의 핵심

웹 페이지의 시각적 표현을 담당하는 스타일 언어.

Spring

자바 웹 프레임워크

기업급 애플리케이션 개발을 위한 강력한 프레임워크.

JavaScript/개념 조각

자바스크립트 프로토타입(Prototype)

lamarcK 2025. 3. 26. 10:40

자바스크립트는 클래스(class) 기반 언어가 아닌 프로토타입(prototype) 기반 언어이다.

객체지향 프로그래밍을 할 때 클래스에서 객체를 찍어내는 방식(Java, C++, Python 등)이 아니라, 기존 객체(프로토타입)를 복사하고 수정해서 새로운 객체를 만드는 방식을 사용한다.

 

프로토 타입(Prototype)이란?

자바스크립트에서 객체는 다른 객체의 값을 상속 받을 수 있으며, 그 기반이 되는 객체를 '프로토타입'이라고 한다.
프로토타입은 말 그대로 원본, 원형, 시제품의 의미이며 새로운 객체의 거푸집(몰드, 형틀) 역할을 한다.

상속?

  • 원본이 되는 객체(프로토타입)의 속성과 메서드과 메서드를 '참조'한다는 의미다. 원본 데이터는 그대로 존재하고 메모리 주소를 참조하는 방식에 가깝다.
  • 즉 원본 데이터를 복사해서 붙여넣는 방식이 아닌 원본 데이터에 접근하고 사용할 수 있는 것이다. 다만 어디까지나 참조이기 때문에 원본 데이터를 수정하거나 삭제하는 등 변경하는 것은 불가능하다.

폐쇄형 구조에도 접근이 가능한가?

  • 자바 스크립트에는 1. 클로저, 2. 즉시 실행 함수 표현식(IIFE), 3. 모듈, 4. 심볼 같은 폐쇄형 구조의 코드들이 있긴하지만 해당 코드가 외부와 단절됐다는 것이지(외부로부터의 직접적인 접근을 제한하고 내부 데이터를 보호한다)
  • 해당 코드에게서 상속을 받은 새로운 객체를 만들지 못한다는 것은 아니다.
  • 기본적으로 모든 객체는 다른 모든 객체에게서 상속 받을 수 있다.

프로토타입 체인(Prototype Chain)

  • 객체의 프로토타입이 또 다른 프로토타입을 가리키는 방식으로 연결되어 있는 것을 프로토타입 체인이라고 한다.
  • 말 그대로 B가 A를 상속 받고 C가 B를 상속 받아서 A-B-C 식으로 연결되어 있다는 것이다.
  • 여기서 C는 자신과 연결된 B에서 속성이나 메서드를 찾지 못하면 A까지 거슬러 올라가면서 찾게된다.
  • 즉 자신이 상속받은 프로토타입이 있다면, 해당 프로토타입의 상위 프로토타입까지 참조를 통한 접근을 허용하는 것이라고 보면 된다.
  • 때문에 객체에서 속성이나 메서드를 찾을 때, 해당 객체에서 찾지 못하면 프로토타입 체인을 따라 올라가면서 찾는다.

프로토타입 비유 및 예시

  • 가족 관계 비유: 프로토타입을 가족 관계에 비유하면, 부모로부터 유전자를 물려받는 자식과 같습니다. 자식은 부모의 유전자를 상속받아 특정 특성을 가지게 되며, 부모가 가진 특성이 자식에게도 전달되는 것과 같습니다.

프로토 타입 연결 방식

  • 객체 연결
    • 자바스크립트의 모든 객체는 [[Prototype]]이라는 숨겨진 내부 슬롯을 가지고 있다.
    • 이 슬롯은 다른 객체 또는 null을 가리키며, 이 연결을 통해 객체 간에 상속 관계를 형성한다.
    • 해당 슬롯은 1개뿐이라 1개의 객체가 여러개의 프로토타입을 한 번에 상속 받는 것은 불가능하다.
  • 프로토타입 체인
    • 하지만 프로토타입 객체 또한 [[Prototype]]을 통해 다른 프로토타입 객체에게 상속 받을 수 있다.
    • 객체에서 특정 속성이나 메서드를 찾을 때, 해당 객체에 없으면 [[Prototype]]을 따라 연결된 상위 프로토타입 객체에서 찾는다.
    • 이러한 방식으로 하위 객체는 상위 프로토타입 객체의 속성과 메서드를 상속받아 사용할 수 있다.
    • 이처럼 객체는 한 번에 1개의 프로토타입을 가지지 못하더라도 실제로는 여러개의 프로토타입으로 부터 상속을 받는 효과를 낼 수 있다.
    • 이러한 프로토타입 객체들의 연결을 프로토타입 체인이라고 한다.

예시

자바스크립트에서 프로토타입 연결 방법은 크게 두 가지로 나눌 수 있다.

객체 리터럴을 사용하는 방법과 생성자 함수를 사용하는 방법이다.

1. 객체 리터럴을 사용하는 방법

Object.create() 메서드: 이 메서드는 지정된 프로토타입 객체를 사용하여 새 객체를 생성한다.

const parent = {
  sayHello() {
    console.log("안녕하세요!");
  },
};

const child = Object.create(parent);
child.name = "아이";

child.sayHello(); // "안녕하세요!"
console.log(child.__proto__ === parent); // true
 

2. 생성자 함수를 사용하는 방법

생성자 함수의 prototype 프로퍼티: 생성자 함수로 생성된 모든 객체는 생성자 함수의 prototype 프로퍼티를 프로토타입으로 갖는다.

function Parent(name) {
  this.name = name;
}

Parent.prototype.sayHello = function () {
  console.log(`안녕하세요, 제 이름은 ${this.name}입니다.`);
};

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

// Child의 프로토타입을 Parent의 프로토타입으로 설정
Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child; // constructor 프로퍼티를 다시 Child로 설정

const child1 = new Child("아이", 10);
child1.sayHello(); // "안녕하세요, 제 이름은 아이입니다."

console.log(child1.__proto__.__proto__ === Parent.prototype); // true

 

 

3. __proto__ 접근자 프로퍼티를 사용하는 방법

const parent = {
  sayHello() {
    console.log("안녕하세요!");
  },
};

const child = {
  name: "아이",
};

child.__proto__ = parent;

child.sayHello(); // "안녕하세요!"
console.log(child.__proto__ === parent); // true

 

  • __proto__ 접근자 프로퍼티: 이 프로퍼티를 사용하여 객체의 프로토타입을 직접 설정할 수 있다.
  • 하지만 Object.getPrototypeOf() 및 Object.setPrototypeOf() 메서드를 사용하는 것이 더 안전하고 권장된다.

4. Object.setPrototypeOf() 를 사용하는 방법

// 부모 객체
const parent1 = {
  sayHello() {
    console.log('부모1이 말합니다. 안녕하세요!');
  },
};

const parent2 = {
  sayHello() {
    console.log('부모2가 말합니다. 안녕하세요!');
  },
  sayGoodbye() {
    console.log('부모2가 말합니다. 안녕히 가세요!');
  },
};

// 자식 객체
const child = {
  name: '아이',
};

// 초기 프로토타입 설정: parent1
Object.setPrototypeOf(child, parent1);

// child 객체에서 parent1의 메서드 사용
child.sayHello(); // "부모1이 말합니다. 안녕하세요!"

// 현재 프로토타입 확인
console.log(Object.getPrototypeOf(child) === parent1); // true

// 프로토타입 변경: parent2
Object.setPrototypeOf(child, parent2);

// child 객체에서 parent2의 메서드 사용
child.sayHello(); // "부모2가 말합니다. 안녕하세요!"
child.sayGoodbye(); // "부모2가 말합니다. 안녕히 가세요!"

// 변경된 프로토타입 확인
console.log(Object.getPrototypeOf(child) === parent2); // true

 

  • parent1과 parent2 객체 생성: 두 개의 부모 객체를 생성하고 각각 다른 sayHello() 메서드를 정의한다.
    • parent2는 추가적으로 sayGoodbye() 메서드도 가지고 있다.
  • child 객체 생성: 자식 객체를 생성하고 name 속성을 정의한다.
  • 초기 프로토타입 설정 (Object.setPrototypeOf()): Object.setPrototypeOf()를 사용하여 child 객체의 프로토타입을 parent1 객체로 설정한다.
  • 초기 프로토타입 메서드 사용: child 객체에서 parent1의 sayHello() 메서드를 호출하고, Object.getPrototypeOf()를 사용하여 child의 현재 프로토타입을 확인한다.
  • 프로토타입 변경 (Object.setPrototypeOf()): Object.setPrototypeOf()를 다시 사용하여 child 객체의 프로토타입을 parent2 객체로 변경한다.
  • 변경된 프로토타입 메서드 사용: child 객체에서 parent2의 sayHello() 및 sayGoodbye() 메서드를 호출하고, Object.getPrototypeOf()를 사용하여 child의 변경된 프로토타입을 확인한다.