객체 지향 프로그래밍(OOP, Object-oriented programming)은 사람이 세계를 보고 이해하는 방법과 매우 흡사합니다. 코드를 추상화하여 직관적으로 생각할 수 있기 때문에, 이미 오래전부터 프로그래밍 방법론으로 매우 빠르게 적용되었습니다.
객체 지향 프로그래밍을 철저하게 적용한 프로그래밍 언어 Java나 C#과는 다르게, JavaScript에서 OOP를 구현하는 방법은 조금 독특합니다. 이번 유닛에서는 JavaScript로 직접 객체 지향 프로그래밍을 구현하며, 객체 지향 프로그래밍의 장점과 각종 용어들을 이해합니다.
객체 지향 프로그래밍은, 절차 지향 프로그래밍과는 다르게 데이터와 기능을 한 곳에 묶어서 처리합니다. 속성과 메서드가 하나의 "객체"라는 개념에 포함되며, 이는 JavaScript 내장 타입인 object
(이하, object literal)와는 다르게, 클래스(Class)라는 이름으로 부릅니다. 이번 챕터에서는 클로저 모듈 패턴, 클래스와 인스턴스에 대해 학습합니다.
애플리케이션을 만들 때 좋은 설계를 하기 위해서는, 기본적으로 이 객체지향을 이해하고 응용하는 것이 중요합니다.
💡 객체 지향 프로그래밍의 주요 개념을 소개합니다.
캡슐화는 코드가 복잡하지 않게 만들고, 재사용성을 높입니다.
추상화는 마찬가지로 코드가 복잡하지 않게 만들고, 단순화된 사용으로 변화에 대한 영향을 최소화합니다.
상속 역시 불필요한 코드를 줄여 재사용성을 높입니다.
다형성으로 인해 동일한 메서드에 대해 if/else if와 같은 조건문 대신
객체의 특성에 맞게 달리 작성하는 것이 가능해집니다.
메서드 호출은 객체.메서드()
와 같이 객체 내에 메서드를 호출하는 방법을 의미합니다.
단순 객체를 사용한 이러한 예제를 흔히 볼 수 있습니다. 다음은 카운터를 구현한 예제입니다.
⚠️ 메서드 호출 방식을 이용할 때에는 화살표 함수를 쓰지 않습니다.
그 이유는 mdn 화살표 함수 설명에서 찾을 수 있습니다.
let counter1 = {
value: 0,
increase: function() {
this.value++ // 메서드 호출을 할 경우, this는 counter1을 가리킵니다
},
decrease: function() {
this.value--
},
getValue: function() {
return this.value
}
}
counter1.increase()
counter1.increase()
counter1.increase()
counter1.decrease()
counter1.getValue() // 2
위의 함수 counter1
은 단 하나의 객체만 만들 수 있습니다. 만약 똑같은 기능을 하는 카운터가 여러 개가 필요하다면,
이 코드를 여러 번 만들어야 할까요? 같은 코드를 그대로 복사/붙여넣기 해야 하므로, 재사용성이 떨어집니다.
똑같은 기능을 하는 카운터를 여러 개 만드는 방법 중 하나는,
아래 예제 코드와 같이 클로저 모듈 패턴을 이용할 수 있습니다.
function makeCounter() {
let value = 0;
return {
increase: function() {
value++;
},
decrease: function() {
value--;
},
getValue: function() {
return value;
}
}
}
let counter1 = makeCounter()
counter1.increase()
counter1.getValue() // 1
let counter2 = makeCounter()
counter2.decrease()
counter2.decrease()
counter2.getValue() // -2
객체를 어떤 식으로 만드는지 살펴보면, 그냥 일반적인 함수를 정의하듯 만듭니다.
이때 함수를 이용하는 방법이 조금 다릅니다.
그냥 실행하는 것이 아니고 new 키워드를 써서 만듭니다.
이는 새로운 인스턴스를 만드는 방법입니다.
일반적인 다른 함수와 구분하기 위해 클래스는 보통 대문자로 시작하며 일반명사로 만듭니다.
일반적인 함수는 적절한 동사를 포함하고 소문자로 시작합니다.
this라는 새로운 키워드가 등장합니다.
객체지향 프로그래밍에서는 빠지지 않고, 등장하므로 간단하게 알아둡시다.
한마디로 this는 인스턴스 객체를 의미합니다.
parameter로 넘어온 브랜드, 이름, 색상 등은 인스턴스 생성 시 지정하는 값이며,
위와 같이 this에 할당한다는 것은 만들어진 인스턴스에 해당 브랜드, 이름, 색상을 부여하겠다는 의미입니다.
이번엔 메서드 정의입니다.
ES5는 prototype이라는 키워드를 사용해야 메서드를 정의할 수 있습니다.
Car 클래스에 메서드를 추가하기 위해서는 Car.prototype.refuel
과 같이 prototype
을 이용해야 합니다.
이후 prototype
에 대해서 자세히 공부하고, 지금은 메서드 정의 시 사용법만 숙지합니다.
ES6에서는 생성자 함수와 함께 class 키워드 안쪽에 묶어서 정의합니다.
refuel() {}
, drive() {}
와 같이 작성되어 있는 부분입니다.
인스턴스를 만들 때에는 new 키워드를 사용합니다.
즉시 생성자 함수가 실행되며, 변수에 클래스의 설계를 가진 새로운 객체, 즉 인스턴스가 할당됩니다.
각각의 인스턴스는 클래스의 고유한 속성과 메서드를 갖게 됩니다.
class Counter {
constructor() {
this.value = 0; // 생성자 호출을 할 경우, this는 new 키워드로 생성한 Counter의 인스턴스입니다
}
increase() {
this.value++
}
decrease() {
this.value--
}
getValue() {
return this.value
}
}
let counter1 = new Counter() // 생성자 호출
counter1.increase()
counter1.getValue() // 1