많은 타 프로그래밍 언어를 공부한 후에 자바스크립트를 입문한 나에게 누군가가 자바스크립트에서 이해하기 가장 어려웠던 개념이 무엇이었는지를 물어본다면, 나는 망설임 없이 자바스크립트에서의 객체 지향이라고 답할 것이다.
보통 클래스(Class)
는 객체 지향 프로그래밍을 이해하는데 있어 가장 중요한 개념이며, C++나 Java와 같은 대표적인 언어들이 크래스 기반의 객체지향 프로그래밍을 지원한다. 하지만 자바스크립트는 설계 당시부터 클래스라는 개념을 배제한 채, 생소한 개념인 프로토타입(prototype) 기반의 객체 지향 프로그래밍을 지원하도록 만들어졌다.
물론 자바스크립트도 ECMAScript 6(ES6) 버전부터 본격적으로 클래스를 지원하기 시작했지만 이 클래스 문법 자체도 내부적으로는 프로토타입으로 구현되어 있다고 할 수 있다.
지금 자바스크립트 코드를 작성한다면 굳이 프로토타입이라는 괴상한 방법을 사용할 필요 없이 단순히 클래스 문법을 사용하면 될 것이다. 하지만 ES6가 지원되기 전에 작성된 라이브러리의 내부 구현을 들여다보면 프로토타입을 사용한 코드를 쉽게 볼 수 있으며, 이를 이해하기 위해서는 ES6 이전에 자바스크립트에서 객체지향을 어떻게 사용했는지 이해할 할 필요가 있다.
이해하기도 어렵고 익숙해지기도 어려운 자바스크립트의 객체 지향 프로그래밍이다. 따라서 내가 공부한 내용을 다른 분들과 공유하기 위해 자바스크립트 객체 지향 프로그래밍 시리즈를 작성하고자 한다. 본 시리즈는
순서로 포스팅을 할 것이며, 이 첫 번째 포스팅에서는 객체 지향 프로그래밍이 무엇인가에 대해 개념 위주로 설명하고자 한다. 객체 지향 프로그래밍의 개념이 이미 무엇인지 알고 있다면 바로 세 번째 포스팅으로 넘어가시면 된다.
객체 지향 프로그래밍
이라는 단어가 처음 프로그래밍을 접한 사람들에게 낯설게 느껴지는 이유는 객체라는 단어 자체를 우리 실생활에서 잘 사용하지 않기 때문일 것이다. 대체 객체라는게 뭐길래 프로그래밍에서 지향한다는 것일까?
이 질문은 내가 처음 프로그래밍을 공부할 때에도 가지던 의문이었고, 이를 좀 더 쉽게 이해하기 위해서 나는 객체 지향이라는 용어 대신 개념 중심이라는 용어를 사용했다.
개념 중심에서 말하는 개념이 뭘 의미하는 걸까? 개념의 사전적 의미는 다음과 같다.
어떤 사물이나 현상에 대한 일반적인 지식.
방금 지나간 빨간색 옷을 입은 사람
은 개념이 아니다. 하지만, 사람
은 개념이다. 즉 하나의 특정 물체만을 의미하는 것이 아니라, 공통점을 가진 여러 물체를 한 번에 묶을 수 있는 포괄적인 정의를 가지는 단어를 개념이라고 한다.
우리는 이 '사람'이라는 개념에 (방금 지나간, 빨간색 옷을 입은)
이라는 특징들을 추가해 특정한 물체를 만들어낼 수 있다. 이것이 바로 개념 중심 프로그래밍, 즉 객체 지향 프로그래밍이 동작하는 방식이다.
자동차
라는 개념을 예로 들어보자. '자동차'는 어떤 특정 모델의 차량을 가리키는 것이 아니기 때문에 개념이다. '자동차'라는 개념에 해당되는 모든 물체들은 공통적으로 가지고 있는 특징들이 존재한다. 예를 들어 모델명, 제조사, 제조일, 소유자 등이 특징이 될 수 있을 것이다. 그리고 우리가 이 자동차라는 개념의 특징에 다음과 같은 값들을 부여하게 되면,
모델명: E300 e 4MATIC
제조사: 메르세데스 벤츠
제조일: 2020-06-22
최고속도: 130 mph
연비: 10.0km/ℓ
연료 잔량: 30ℓ
소유자: 홍길동
아래와 같은 홍길동이 소유하고 있는 메르세데스 벤츠 E 클래스 자동차
라는 물체가 생성된다.
즉, 개념이 가지는 공통적인 특징들에 값을 부여해줌으로써 특정한 물체를 정의할 수 있으며, 이것이 바로 객체 지향 프로그래밍에서 클래스의 클래스 변수들에 값을 할당해줌으로써 객체를 정의하는 과정과 동일하다고 할 수 있다.
이처럼 클래스를 개념으로, 객체를 물체로 치환하여 OOP를 다시 보면 이전보다 훨씬 이해하기 쉬울 것이라고 생각한다. 객체 지향 용어에 아직 익숙하지 않다면 이해를 위해 더 쉬운 용어로 바꿔서 이해해보자.
객체 지향 프로그래밍의 정의에 대한 설명은 여기까지 하고, 위 설명에서 빠뜨린 부분에 대해 짚고 넘어가고자 한다. 우리가 클래스를 정의할 때에는 단순히 공통되는 특징을 클래스 변수로 정의해주는 것 뿐만 아니라, 공통되는 행동을 클래스 함수, 즉 메소드
로 정의해준다.
위의 '자동차' 예제를 살펴보면, '자동차'라는 클래스에는 다음과 같은 클래스 변수들을 정의할 수 있을 것이다.
클래스 자동차 {
생성자(model, company, manDate, topSpeed, fuelEf, fuelRemain, owner){
this.model = model; // 모델명
this.company = company; // 제조사
this.manDate = manDate; // 제조일
this.topSpeed = topSpeed; // 최고속도
this.fuelEf = fuelEf; // 연비
this.fuelRemain = fuelRamain; // 연료 잔량
this.owner = owner; // 소유자
}
}
생성자는 지금은 이해하지 않아도 되고, 우리가 자동차 클래스에 특징 값들을 부여해 객체를 만들 때, 이 특징 값들을 인자로 받아 객체를 만들어주는 함수라고 생각하면 된다.
하지만 모든 자동차는 공통되는 특징 뿐만이 아니라, '운전하다'라는 공통되는 행동 또한 가진다. 현재 고장나서 작동하지 않는 자동차라고 하더라고 '운전하다'라는 기능 자체는 가지고 있을 것이기 때문이다.
따라서, Car 클래스에 다음과 같이 'Drive'라는 공통되는 행동을 메소드를 추가할 수 있다.
클래스 자동차 {
생성자(model, company, manDate, topSpeed, fuelEf, fuelRemain, owner){
...생략
}
function 운전하다(){
// 자동차를 최대 속도로 1시간동안 운전하는 함수
// 자동차의 이동 거리를 반환한다.
}
}
이렇게 클래스에 메소드를 추가하면, 앞으로 우리가 특징 값들을 부여해서 만들어내는 모든 '자동차' 객체는 기본적으로 '운전하다'라는 행동을 탑재하게 된다. 그리고 이 '운전하다' 함수를 구현할 때에는 현재 객체가 가지고 있는 특징 값에 따라 다르게 동작하게 만들 수 있기 때문에, 티코 자동차
객체가 '운전하다' 함수를 호출했을 때와 벤츠 E 클래스 자동차
객체가 '운전하다' 함수를 호출했을 때의 자동차 이동 거리 결과를 다르게 얻을 수 있다.
정리하자면, '객체 지향 프로그래밍'은 '개념 중심 프로그래밍'으로 바꿔 생각하면 이해하기 쉬우며, 객체 지향 프로그래밍의
클래스에 클래스 변수와 메소드를 정의한 후, 인자를 통해 객체(클래스 인스턴스)를 생성한다.
라는 말은
개념이 가지는 공통된 특징들과 공통된 동작들을 정의한 후, 특징에 특징 값들을 배정하여 물체를 생성한다.
라는 말로 해석될 수 있다.
객체 지향 프로그래밍이 뭔지를 이해하는데 어려움을 겪고 있는 분들에게 조금이나마 도움이 되었으면 한다. 다음 포스팅에서는 객체 지향 프로그래밍의 4대 특징에 대해 알아보도록 하자.