# 객체 지향 프로그래밍(Object-Oriented Programming, OOP) 자바스크립트는 객체 지향 프로그래밍(OOP)의 패러다임을 지원합니다. OOP는 프로그램을 **객체(object)**라는 독립적인 단위로 나누고, 이 객체들 간의 상호작용으로 문제를 해결하는 방법론입니다. 자바스크립트는 클래스와 프로토타입 기반 객체 지향 프로그래밍을 모두 지원합니다. ## OOP **객체 지향 프로그래밍(OOP)**의 핵심은 데이터를 **객체(object)**로 구조화하는 것입니다. 객체는 **속성(property)**과 **메서드(method)**를 가지며, 현실 세계의 개념을 코드로 추상화합니다. ### OOP의 주요 원칙 - 캡슐화 (Encapsulation): 객체 내부의 데이터를 외부로부터 숨기고, 필요한 인터페이스만 노출합니다. - 상속 (Inheritance): 기존 객체(클래스)의 속성과 메서드를 재사용하여 새로운 객체를 생성합니다. - 다형성 (Polymorphism): 같은 메서드 이름이 다른 객체에서 다르게 동작하도록 합니다. - 추상화 (Abstraction): 복잡한 구현을 감추고, 필요한 핵심만 노출합니다. ### OOP의 주요 장점 - 코드 재사용성: 상속과 클래스 설계를 통해 동일한 코드를 반복하지 않고 재사용할 수 있습니다. - 유지보수 용이성: 캡슐화와 모듈화를 통해 코드의 구조가 명확해지고 수정이 쉬워집니다. - 확장성: 새로운 클래스나 메서드를 쉽게 추가할 수 있습니다. - 가독성: 객체를 통해 프로그램의 논리를 현실 세계와 유사하게 표현할 수 있습니다. ### OOP와 자바스크립트의 유연성 자바스크립트는 객체 지향 프로그래밍 외에도 함수형 프로그래밍이나 절차적 프로그래밍을 지원합니다. 즉, 필요에 따라 객체 지향적인 스타일과 함수형 스타일을 혼합하여 사용할 수 있는 멀티 패러다임 언어입니다. ## 자바스크립트의 객체 지향 구현 방법 ### 객체 리터럴 가장 기본적인 객체 생성 방식은 객체 리터럴을 사용하는 것입니다. ```javascript const person = { name: "홍길동", age: 30, greet: function () { console.log(`안녕하세요, 제 이름은 ${this.name}입니다.`); }, }; person.greet(); // 출력: 안녕하세요, 제 이름은 홍길동입니다. ``` ### 생성자 함수 (Constructor Function) 생성자 함수는 객체를 생성하는 데 사용됩니다. ```javascript function Person(name, age) { this.name = name; this.age = age; this.greet = function () { console.log(`안녕하세요, 저는 ${this.name}이고, 나이는 ${this.age}살입니다.`); }; } const person1 = new Person("김철수", 25); const person2 = new Person("박영희", 28); person1.greet(); // 출력: 안녕하세요, 저는 김철수이고, 나이는 25살입니다. person2.greet(); // 출력: 안녕하세요, 저는 박영희이고, 나이는 28살입니다. ``` ### 프로토타입 (Prototype) 자바스크립트는 프로토타입 기반 언어로, 모든 객체는 자신의 프로토타입을 참조합니다. 프로토타입은 객체가 상속받을 수 있는 속성과 메서드를 정의합니다. ```javascript function Person(name, age) { this.name = name; this.age = age; } Person.prototype.greet = function () { console.log(`안녕하세요, 저는 ${this.name}이고, 나이는 ${this.age}살입니다.`); }; const person1 = new Person("김철수", 25); const person2 = new Person("박영희", 28); person1.greet(); // 출력: 안녕하세요, 저는 김철수이고, 나이는 25살입니다. person2.greet(); // 출력: 안녕하세요, 저는 박영희이고, 나이는 28살입니다. ``` ### 클래스 (Class) ES6부터 클래스를 사용하여 객체 지향 프로그래밍을 더욱 간단하고 직관적으로 구현할 수 있습니다. 클래스는 생성자 함수의 문법적 설탕(Syntactic Sugar)입니다. * 클래스를 선언하려면 class 키워드와 함께 클래스의 이름을 작성합니다. * 클래스 선언은 let과 const처럼 블록 스코프에 선언되며, 호이스팅(hoisting)이 일어나지 않는다. 클래스는 반드시 정의한 뒤에 사용해야 합니다. * 클래스의 메소드 안에서 super 키워드를 사용할 수 있습니다. * static 키워드를 메소드 이름 앞에 붙여주면 해당 메소드는 정적 메소드가 됩니다. * Getter 혹은 Setter를 정의하고 싶을 때는 메소드 이름 앞에 get 또는 set을 붙여주면 된다. * extends 키워드를 사용하여 클래스에서 다른 클래스로 상속하면서 클래스의 기능을 확장해 나갈수 있습니다. * 클래스에서 일반적인 방식으로 프로퍼티를 선언하고 할당하면 Public Property(공개 프로퍼티)입니다. * 클래스에서 프로퍼티 앞에 # 키워드를 작성하여 선언하면 Private Property (비공개 프로퍼티)가 됩니다. #### 클래스 선언 ```javascript class Person { constructor(name, age) { this.name = name; this.age = age; } greet() { console.log(`안녕하세요, 저는 ${this.name}이고, 나이는 ${this.age}살입니다.`); } } const person1 = new Person("이철수", 40); const person2 = new Person("한지민", 35); person1.greet(); // 출력: 안녕하세요, 저는 이철수이고, 나이는 40살입니다. person2.greet(); // 출력: 안녕하세요, 저는 한지민이고, 나이는 35살입니다. ``` * class 키워드: 클래스를 선언하는 데 사용됩니다. * constructor(): 객체 생성 시 호출되는 생성자 메서드입니다. * 메서드: 클래스 내에 정의된 함수를 의미합니다. * new 키워드를 사용하여 클래스의 인스턴스를 생성합니다. #### 상속 (Inheritance) 클래스 간 상속을 통해 코드를 재사용할 수 있습니다. 자바스크립트에서 클래스는 extends 키워드를 사용하여 상속을 구현합니다. ```javascript class Animal { constructor(name) { this.name = name; } sound() { console.log(`${this.name}가 소리를 냅니다.`); } } class Dog extends Animal { sound() { console.log(`${this.name}가 멍멍 짖습니다.`); } } const dog = new Dog("강아지"); dog.sound(); // 출력: 강아지가 멍멍 짖습니다. ``` * extends 키워드: 다른 클래스를 상속받아 새로운 클래스를 정의합니다. * super(): 부모 클래스의 생성자를 호출합니다. #### 다형성 (Polymorphism) 다형성은 상속 관계에서 메서드를 재정의(오버라이딩)하여 구현됩니다. ```javascript class Animal { speak() { console.log("동물이 소리를 냅니다."); } } class Cat extends Animal { speak() { console.log("고양이가 야옹합니다."); } } class Dog extends Animal { speak() { console.log("강아지가 멍멍 짖습니다."); } } const animals = [new Cat(), new Dog(), new Animal()]; animals.forEach(animal => animal.speak()); // 출력: // 고양이가 야옹합니다. // 강아지가 멍멍 짖습니다. // 동물이 소리를 냅니다. ``` #### 정적 필드 / 메서드 정적 필드는 클래스 자체에 속하는 필드로, 인스턴스를 생성하지 않고도 클래스 이름으로 직접 접근할 수 있는 필드입니다. ```javascript class MathUtils { static PI = 3.14159; static square(x) { return x * x; } } console.log(MathUtils.PI); // 3.14159 console.log(MathUtils.square(5)); // 25 ``` #### Getter / Setter ```javascript class Person { #name; // private 속성 #age; constructor(name, age) { this.#name = name; this.#age = age; } get name() { return this.#name; } set name(value) { this.#name = value; } } const person1 = new Person('홍길동', 30); console.log(person1.name); // 홍길동 (getter를 통해 접근) console.log(person1.#name); // Error: Property '#name' is private ``` * get과 set을 사용하여 속성에 대한 접근을 제어할 수 있습니다.