JavaScript Prototype

자바스크립트의 프로토타입(Prototype)은 객체 지향 프로그래밍을 구현하는데 핵심적인 개념입니다. 자바스크립트는 프로토타입 기반 상속을 사용하며, 이를 통해 객체와 함수가 프로토타입 체인을 통해 서로 상호작용하고 상속 관계를 형성할 수 있습니다.

1. 프로토타입의 기본 개념

자바스크립트의 모든 객체는 다른 객체로부터 메서드와 속성을 상속받기 위해 __proto__(또는 [[Prototype]])라는 숨겨진 속성을 가집니다. 이는 프로토타입 체인을 형성하여 객체의 상속 관계를 정의합니다.

1.1 객체 생성과 프로토타입

객체 리터럴로 생성된 객체의 프로토타입은 Object.prototype입니다.

const obj = {};
console.log(obj.__proto__ === Object.prototype); // true

생성자 함수로 생성된 객체는 해당 생성자 함수의 prototype 속성을 프로토타입으로 갖습니다.

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

const person = new Person('Alice');
console.log(person.__proto__ === Person.prototype); // true

1.2 프로토타입 체인

객체가 특정 속성이나 메서드를 찾지 못하면 프로토타입 체인을 따라가면서 검색을 계속합니다. 최종적으로 Object.prototype까지 검색을 시도하고, 그래도 찾지 못하면 undefined를 반환합니다.

const obj = { a: 1 };
console.log(obj.toString()); // [object Object] (Object.prototype의 메서드)
console.log(obj.hasOwnProperty('a')); // true (Object.prototype의 메서드)

2. 생성자 함수와 프로토타입

생성자 함수는 새로운 객체를 만들 때 그 객체의 프로토타입을 정의합니다. 모든 생성자 함수는 prototype 속성을 가지며, 이 속성은 해당 생성자 함수로 생성된 모든 객체의 프로토타입이 됩니다.

function Animal(type) {
  this.type = type;
}

Animal.prototype.speak = function() {
  console.log(`The ${this.type} makes a sound`);
};

const dog = new Animal('dog');
dog.speak(); // The dog makes a sound

위 예제에서 speak 메서드는 Animal.prototype에 정의되어 있으며, dog 객체에서 사용할 수 있습니다.

3. 프로토타입 상속

프로토타입 상속을 통해 객체는 다른 객체의 속성과 메서드를 상속받을 수 있습니다. 이를 통해 재사용성과 코드의 유지보수성을 높일 수 있습니다.

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

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}`);
};

function Student(name, grade) {
  Person.call(this, name); // Person 생성자 함수 호출
  this.grade = grade;
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.study = function() {
  console.log(`${this.name} is studying`);
};

const student = new Student('Alice', 'A');
student.greet(); // Hello, my name is Alice
student.study(); // Alice is studying

위 예제에서 StudentPerson을 상속받아 greet 메서드를 사용할 수 있으며, 추가로 study 메서드를 정의하여 사용할 수 있습니다.

4. 프로토타입의 동적 변경

프로토타입은 동적으로 변경될 수 있으며, 이는 모든 인스턴스에 영향을 미칩니다.

function Car(model) {
  this.model = model;
}

const car1 = new Car('Toyota');
const car2 = new Car('Honda');

Car.prototype.drive = function() {
  console.log(`${this.model} is driving`);
};

car1.drive(); // Toyota is driving
car2.drive(); // Honda is driving

Car.prototype.drive = function() {
  console.log(`${this.model} is moving`);
};

car1.drive(); // Toyota is moving
car2.drive(); // Honda is moving

위 예제에서 Car.prototype.drive를 동적으로 변경하면, car1car2 모두 변경된 drive 메서드를 사용합니다.

5. ES6 클래스와 프로토타입

ES6 클래스 문법은 프로토타입 기반 상속을 더욱 간결하고 직관적으로 사용할 수 있게 합니다. 클래스는 사실상 프로토타입을 사용하는 문법적 설탕입니다.

class Animal {
  constructor(type) {
    this.type = type;
  }

  speak() {
    console.log(`The ${this.type} makes a sound`);
  }
}

class Dog extends Animal {
  constructor(type, name) {
    super(type); // 부모 클래스 생성자 호출
    this.name = name;
  }

  bark() {
    console.log(`${this.name} is barking`);
  }
}

const dog = new Dog('dog', 'Rex');
dog.speak(); // The dog makes a sound
dog.bark(); // Rex is barking

위 예제에서 Dog 클래스는 Animal 클래스를 상속받아 speak 메서드를 사용하고, 추가로 bark 메서드를 정의합니다.

6. 프로토타입 메서드와 인스턴스 메서드

프로토타입 메서드는 모든 인스턴스가 공유하는 메서드입니다. 반면, 인스턴스 메서드는 각 인스턴스마다 개별적으로 존재합니다.

function Gadget(name) {
  this.name = name;
  this.sayName = function() {
    console.log(this.name);
  };
}

Gadget.prototype.sayHello = function() {
  console.log(`Hello, ${this.name}`);
};

const gadget1 = new Gadget('Phone');
const gadget2 = new Gadget('Tablet');

gadget1.sayHello(); // Hello, Phone
gadget2.sayHello(); // Hello, Tablet

gadget1.sayName(); // Phone
gadget2.sayName(); // Tablet

위 예제에서 sayHello는 프로토타입 메서드로 모든 인스턴스가 공유하지만, sayName은 인스턴스 메서드로 각 인스턴스마다 개별적으로 존재합니다.

7. 프로토타입 상속과 Object.create

Object.create 메서드는 특정 객체를 프로토타입으로 가지는 새로운 객체를 생성합니다.

const person = {
  greet() {
    console.log('Hello');
  }
};

const friend = Object.create(person);
friend.greet(); // Hello

위 예제에서 friend 객체는 person 객체를 프로토타입으로 가지며, greet 메서드를 상속받습니다.

8. 프로토타입 체인의 예

function A() {}
function B() {}

B.prototype = Object.create(A.prototype);
B.prototype.constructor = B;

const b = new B();

console.log(b instanceof A); // true
console.log(b instanceof B); // true

위 예제에서 b 객체는 BA 모두의 인스턴스입니다. 이는 프로토타입 체인을 통해 이루어집니다.

9. 정적 메서드와 프로토타입 메서드

클래스에서 정적 메서드는 인스턴스가 아니라 클래스 자체에 속하는 메서드입니다.

class MyClass {
  static staticMethod() {
    console.log('This is a static method');
  }

  instanceMethod() {
    console.log('This is an instance method');
  }
}

MyClass.staticMethod(); // This is a static method

const myInstance = new MyClass();
myInstance.instanceMethod(); // This is an instance method

위 예제에서 staticMethod는 클래스 자체에서 호출되며, instanceMethod는 인스턴스에서 호출됩니다.

결론

자바스크립트의 프로토타입 개념은 객체 지향 프로그래밍을 구현하는 데 중요한 역할을 합니다. 프로토타입을 이해하면 자바스크립트의 상속과 객체 생성 방식을 더 잘 이해하고, 효율적으로 활용할 수 있습니다. 프로토타입은 코드 재사용성과 성능을 개선하는 데 중요한 도구이며, 이를 잘 활용하면 더욱 강력하고 유연한 자바스크립트 코드를 작성할 수 있습니다.

Leave a Reply

Your email address will not be published. Required fields are marked *