JavaScript 프로토타입: 객체 지향 프로그래밍 이해하기
JavaScript 프로토타입: 객체 지향 프로그래밍 이해하기
JavaScript는 유연하면서도 강력한 언어입니다. 특히, 객체지향 프로그래밍(OOP) 방식을 지원하면서 다른 언어와는 다르게 프로토타입 기반의 상속을 사용합니다. 이 글에서는 JavaScript의 프로토타입 기반 OOP를 이해하고 더 나아가 효율적으로 활용하는 방법에 대해 알아보겠습니다.
객체 생성 및 프로토타입 이해하기
JavaScript에서의 객체는 속성과 메서드의 집합입니다. 객체는 Object
생성자 함수나 객체 리터럴을 사용하여 생성할 수 있습니다. 예를 들어, 다음과 같습니다.
javascript// 객체 리터럴을 사용한 객체 생성 const person = { name: 'John', age: 30, greet() { console.log(`Hello, my name is ${this.name}`); } }; // 객체 사용하는 예 person.greet(); // Outputs: Hello, my name is John
프로토타입은 JavaScript에서 상속을 구현하는 핵심적인 개념입니다. 기본적으로 모든 객체는 __proto__
라는 숨겨진 프로퍼티를 가지며, 이는 자신을 생성한 생성자의 prototype
프로퍼티를 참조합니다. 예를 들어, 위의 person
객체는 Object.prototype
을 상속받습니다.
javascript// 프로토타입 체인 확인 console.log(person.__proto__ === Object.prototype); // true
생성자 함수와 프로토타입
생성자 함수는 새로운 객체를 만들기 위한 템플릿 역할을 합니다. 생성자 함수를 이용하면 여러 객체를 생성할 때 효율적으로 속성과 메서드를 공유할 수 있습니다.
javascript// 생성자 함수 function Person(name, age) { this.name = name; this.age = age; } // 프로토타입 메서드 추가 Person.prototype.greet = function() { console.log(`Hello, my name is ${this.name}`); }; // 새로운 객체 생성 const john = new Person('John', 30); const jane = new Person('Jane', 25); // 메서드 호출 john.greet(); // Outputs: Hello, my name is John jane.greet(); // Outputs: Hello, my name is Jane
위 예제에서 Person
생성자 함수는 name
과 age
속성을 초기화합니다. greet
메서드는 Person.prototype
에 정의되어 있으며, 이를 통해 모든 인스턴스가 공유하게 됩니다. 따라서 john
과 jane
은 각각 자신의 greet
메서드를 호출할 수 있습니다.
프로토타입 체인
프로토타입 체인은 객체 탐색 시 사용되는 메커니즘입니다. 특정 객체에서 프로퍼티를 찾지 못하면, 그 객체의 프로토타입 체인 상위 객체를 탐색합니다. 이 과정은 최종적으로 Object.prototype
에 도달할 때까지 계속됩니다.
javascript// 객체 생성 const obj = { a: 1 }; // 속성 탐색 console.log(obj.a); // Outputs: 1 console.log(obj.toString()); // Outputs: [object Object]
위 예제에서 obj
에는 toString
메서드가 없지만, Object.prototype
에 정의된 toString
을 사용합니다. 이처럼 객체는 프로토타입 체인을 통해 상속 관계를 형성합니다.
클래스와 프로토타입
ES6(ECMAScript 2015)에서 JavaScript는 class
문법을 도입하여 더 깔끔하고 직관적인 객체지향 프로그래밍 스타일을 제공합니다. class
는 사실 함수이며 기존의 프로토타입 기반 상속을 여전히 사용합니다.
javascript// 클래스 정의 class Person { constructor(name, age) { this.name = name; this.age = age; } // 메서드 정의 greet() { console.log(`Hello, my name is ${this.name}`); } } // 객체 생성 const john = new Person('John', 30); const jane = new Person('Jane', 25); // 메서드 호출 john.greet(); // Outputs: Hello, my name is John jane.greet(); // Outputs: Hello, my name is Jane
위 예제에서 Person
클래스는 생성자와 메서드를 정의하고 이를 통해 객체를 생성합니다. 클래스 내부에서 정의된 메서드 역시 프로토타입 체인에 의해 공유됩니다.
상속과 서브클래싱
JavaScript의 class
문법은 쉽게 상속을 구현할 수 있는 방법을 제공합니다. extends
키워드를 사용하여 서브클래스를 정의할 수 있습니다.
javascript// 부모 클래스 class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a noise.`); } } // 자식 클래스 class Dog extends Animal { constructor(name, breed) { super(name); // 부모 클래스의 생성자를 호출 this.breed = breed; } speak() { console.log(`${this.name} barks.`); } } // 객체 생성 const dog = new Dog('Rex', 'German Shepherd'); dog.speak(); // Outputs: Rex barks.
위 예제에서 Dog
클래스는 Animal
클래스를 상속받아 speak
메서드를 오버라이드합니다. super
키워드는 부모 클래스의 생성자를 호출하는 데 사용됩니다.
결론
JavaScript의 프로토타입 기반 객체지향 프로그래밍 방식은 매우 유연하며, 다양한 방법으로 활용할 수 있습니다. 프로토타입 체인을 통해 객체 간 상속 관계를 쉽게 구현할 수 있으며, 도시적 OOP 스타일의 class
문법도 사용할 수 있습니다. 이 글을 통해 JavaScript의 객체지향 프로그래밍 개념을 잘 이해하고 실제 프로젝트에 적용해보세요.