서론
함수형 프로그래밍은 JavaScript 개발에서 중요한 패러다임이다. JavaScript는 함수형 프로그래밍의 여러 중요한 특징들을 지원하여 개발자들이 더 효율적이고 오류가 적은 코드를 작성할 수 있게 한다. 특히, 클로저를 통해 외부 변수를 쉽게 참조할 수 있으며, 1급 객체로서 함수를 값처럼 사용할 수 있어 코드의 유연성과 재사용성을 높인다. 또한, 모나드의 일종인 Promise를 통해 비동기 작업을 체계적으로 처리할 수 있다. 이러한 특징들은 JavaScript를 함수형 패러다임에 매우 적합한 언어로 만든다. 이를 통해 순수 함수로 부작용을 방지하고 불변성을 유지할 수 있어 코드의 안정성과 예측 가능성을 높일 수 있다.
React에서는 이러한 함수형 패러다임을 권장하여 상속보다는 합성을 권장한다. 특히, React의 상태 관리와 업데이트는 함수형 프로그래밍의 이점을 극대화하여 효율적인 상태 관리와 UI 업데이트를 가능하게 한다. 또한 React의 Flux 아키텍처는 함수형 패러다임과 잘 맞는다. 반면, MVC 아키텍처는 주로 객체 지향 프로그래밍과 함께 사용되기에 Angular를 제외한 라이브러리로 프론트개발에서 OOP를 잘 쓰지는 않는 것 같다. 그러나 Vue나 Redux는 클래스 기반으로 구현되어 객체 지향 프로그래밍의 특성을 따른다. 따라서, 프론트엔드 개발에서도 객체 지향 프로그래밍을 이해하고 활용하는 것은 여전히 중요하다. 이 글에서는 javascript에서 OOP 패러다임에 대해 알아보겠다.
배경지식
OOP의 3요소
1. 클래스와 인스턴스
클래스는 꼭 객체 지향 프로그래밍(OOP)을 의미하지 않는다. 클래스는 데이터 타입이며, OOP는 프로그래밍 패러다임이기 때문이다. 그러나 사람들이 사용하는 대부분의 OOP는 클래스를 기반으로 한 OOP이다.
클래스 자체로는 아무런 동작도 하지 않는다. 클래스는 특정 타입의 구체적인 객체를 생성하기 위한 일종의 템플릿이다. 클래스에서 만들어지는 객체는 해당 클래스의 instance라고 한다. 인스턴스를 생성하는 과정은 생성자(constructor)라는 함수를 통해 이루어진다. 새로운 인스턴스를 초기화할 때 생성자에 값을 전달한다. 따라서 인스턴스는 데이터에 의해 구분되는 객체들이다.
2. 상속
상속은 기존 클래스를 기반으로 새로운 클래스를 만드는 기능을 의미한다. 상속을 통해 기존 클래스의 속성과 메서드를 재사용할 수 있으며, 이를 확장하거나 변경하여 새로운 기능을 추가할 수 있다. 한 메서드가 다른 클래스에서 동일한 이름을 가지면서 다른 구현을 가지고 있는 경우, 이를 다형성(polymorphism)이라고 한다. 서브클래스의 메서드가 슈퍼클래스의 구현을 대체하는 경우, 이를 서브클래스가 슈퍼클래스의 버전을 오버라이드(override)한다고 한다.
3. 캡슐화
캡슐화는 객체의 데이터와 메서드를 하나로 묶고, 외부로부터 객체의 내부 상태를 숨기는 것을 의미한다. 캡슐화는 객체의 내부 구현을 외부에 노출하지 않고, 필요한 부분만 공개함으로써 데이터의 무결성을 보장한다. 객체의 내부 상태는 비공개(private)로 유지되며, 이는 객체 자신의 메서드에 의해서만 접근될 수 있고 다른 객체에서는 접근할 수 없다. 캡슐화는 프로그래머가 객체의 내부 구현을 변경하더라도 그것을 사용하는 모든 코드를 찾아 업데이트할 필요가 없게 해주는 유용한 기능이다.
Javascript에서의 OOP
Javascript는 prototype 기반 언어이므로 prototype을 연결(참조)하는 prototype chain은 상속을 구현하는 방법으로 보인다. 하지만 이러한 javascript의 특징과 위에서 설명한 class based 객체 지향 프로그래밍 개념 간에는 차이가 있다.
첫째, class based 객체 지향 프로그래밍에서 클래스와 객체는 두 개의 별도 구조이며, 객체는 항상 클래스의 인스턴스로 생성된다. 또한, 클래스를 정의하는 것과 객체를 인스턴스화하는 것은 서로 다르다. JavaScript에서는 함수나 객체 리터럴을 사용하여 별도의 클래스 정의 없이 객체를 생성할 수 있다.
둘째, prototype chain은 상속 계층처럼 보이지만 상속 계층과 정확히 똑같은 것은 아니다. class based 객체 지향 프로그래밍에서는 서브클래스가 인스턴스화될 때, 서브클래스에 정의된 속성과 상위 계층에 정의된 속성을 결합한 단일 객체가 생성된다. 그러나 prototype chain에서는 계층의 각 수준이 별도의 객체로 표현되며, 이 객체들은 proto 속성을 통해 연결된다. 따라서 prototype chain의 동작은 상속보다는 위임(delegation)과 더 유사하다. 위임은 객체가 작업을 수행하도록 요청받았을 때, 스스로 수행하거나 상위 객체에게 작업을 수행하도록 요청할 수 있는 프로그래밍 패턴이다.
그럼에도 불구하고 생성자와 프로토타입을 사용하여 JavaScript에서 class based OOP 패턴을 구현할 수 있지만 ES6에서 추가된 문법적 설탕인 class 구문을 통해 쉽게 class based OOP 패턴을 구현할 수 있다.
class Person {
name;
constructor(name) {
this.name = name;
}
introduceSelf() {
console.log(`Hi! I'm ${this.name}`);
}
}
위 코드에서 class 문법과 constructor함수를 이용하여 property를 초기화하고, 내부에 method를 선언하는 것을 볼 수 있다. 이제 Person class와 생성자 함수를 이용해서 새로운 인스턴스들을 생성하고, 인스턴스에서 class 내부의 method들을 호출할 수 있다.
class Professor extends Person {
teaches;
constructor(name, teaches) {
super(name);
this.teaches = teaches;
}
introduceSelf() {
console.log(
`My name is ${this.name}, and I will be your ${this.teaches} professor.`,
);
}
grade(paper) {
const grade = Math.floor(Math.random() * (5 - 1) + 1);
console.log(grade);
}
}
extends를 이용해 Person class를 상속받아 새로운 class인 professor를 만들었다. name property는 상위 class에서 정의되어 있는 property이므로 super를 통해 전달하는 모습이다. 똑같은 이름의 method를 다시 정의함으로써 override하고 있는 것을 또한 볼 수 있다.
class Student extends Person {
#year;
constructor(name, year) {
super(name);
this.#year = year;
}
#canStudyArchery() {
return this.#year > 1;
}
}
마지막으로 Javascript에서 private method와 캡슐화를 구현하는 모습이다. 간단하게 method, property앞에 #를 붙이면 된다. 이러면 class 내부에서는 접근 할 수 있지만 인스턴스에서는 접근할 수 없게 된다.
참고자료
- Mozilla Developer Network (MDN). (2024.07.). Classes in JavaScript. Retrieved from MDN Web Docs
- Mozilla Developer Network (MDN). (2024.07.). Object-oriented programming. Retrieved from MDN Web Docs
'JS' 카테고리의 다른 글
[JS] Javascript에서의 FP (0) | 2024.07.24 |
---|---|
[JS] Javascript에서의 모듈 시스템 (1) | 2024.07.23 |
[JS] Javascript에서의 Memory Management (0) | 2024.07.18 |
[JS] Javascript의 프로토타입과 상속: 개념과 동작 이해 (0) | 2024.01.12 |
[JS] Javascript에서의 Closures (1) | 2024.01.11 |