Today I Learned
- 객체 지향
- 클래스와 인스턴스
- 객체 지향 프로그래밍
객체 지향 프로그래밍
(Object Oriented Programming, OOP)은 실세계에 존재하고 인지하고 있는 객체(Object)를 소프트웨어의 세계에서 표현하기 위해 객체의 핵심적인 개념 또는 기능만을 추출하는 추상화(abstraction)를 통해 모델링하려는 프로그래밍 패러다임을 말한다. 다시 말해, 우리가 주변의 실세계에서 사물을 인지하는 방식을 프로그래밍에 접목하려는 사상을 의미한다.
들어가기에 앞서, 자바스크립트는 클래스 기반의 언어(Java, C++, C#, Python 등)가 아닌 프로토타입 기반 언어이다. 클래스 개념이 없고 별도의 객체 생성 방법(객체 리터럴, Object() 생성자 함수, 생성자 함수)이 존재하며 객체 지향의 상속, 캡슐화(정보 은닉) 등의 개념은 프로토타입 체인과 클로저 등으로 구현할 수 있다. 자바스크립트에서는 클래스, 생성자, 메소드도 모두 함수로 구현이 가능하다.
ES6에서 Class 문법이 도입됐는데 여기서의 Class도 사실 함수이며, 기존 prototype 기반 패턴의 Syntactic sugar 일 뿐이다. 즉, 아래서부터 자바스크립트 문법을 예시로 지칭할 클래스는 클래스 기반 언어에서의 클래스와 동일하지 않다는 것을 주의해야 한다.
객체 지향 프로그래밍은 하나의 모델이 되는 청사진(blueprint)을 만들고, 그 청사진을 바탕으로 한 객체를 만드는 프로그래밍 패턴이다.
그냥 객체가 아닌 "청사진"을 바탕으로 한 객체는 인스턴스 객체, 즐여서 인스턴스(instance)라 칭하고, 청사진은 클래스(class)라고 칭한다. 흔한 예시로, 클래스를 붕어빵틀, 인스턴스를 붕어빵에 비유하기도 한다.
일반적인 다른 함수와 구별하기 위해 클래스는 보통 대문자로 시작하여 일반명사를 만든다. (일반적인 함수는 적절한 동사를 포함하고 소문자로 시작한다.)
인스턴스는 new
키워드와 생성자 함수를 이용해 만든다. 각각의 인스턴스는 클래스의 고유한 속성과 메서드를 갖는다.
생성자 함수 블록 내부의 this
는 인스턴스 객체를 의미한다.
ES5 문법
// class
function Car(brand, name, color) {
// 속성 정의
this.brand = brand;
this.name = name;
this.color = color;
}
// 메서드 정의
Car.prototype.drive = function () {
console.log(this.name + '가 운전을 시작합니다');
}
Car.prototype.refuel = function () {
console.log(this.name + '에 연료를 공급합니다');
}
// 여러 개의 instance
let avante = new Car('hyundai', 'avante', 'black');
let mini = new Car('bmw', 'mini', 'white');
ES6 문법
- class 키워드 사용
// class
class Car {
constructor(brand, name, color) {
// 속성 정의
this.brand = brand;
this.name = name;
this.color = color;
}
// 메서드 정의
drive() {
console.log(this.name + '가 운전을 시작합니다');
}
refuel() {
console.log(this.name + '에 연료를 공급합니다');
}
}
// 여러 개의 instance
let avante = new Car('hyundai', 'avante', 'black') ;
let mini = new Car('bmw', 'mini', 'white');
인스턴스에서 속성 및 메서드 사용하기
let avante = new Car('hyundai', 'avante', 'black');
avante.color; // 'black'
avante.drive() // 아반떼가 운전을 시작합니다
let mini = new Car('bmw', 'mini', 'white');
mini.brand // 'bmw'
mini.refuel() // 미니에 연료를 공급합니다
- prototype : 모델의 청사진을 만들 때 쓰는 원형 객체
- constructor : 인스턴스가 초기화될 때 실행하는 생성자 함수
- this : 함수가 실행될 때 해당 scope마다 생성되는 고유한 실행 컨텍스트, new 키워드로 인스턴스를 생성했을 때에는, 해당 인스턴스가 바로 this의 값이 됨
mdn에서 배열 메서드 관련 문서를 보면, Array.prototype.메서드
으로 명시돼있다. 클래스의 원형 객체(prototype)에 메서드들이 정의돼 있는 것을 알 수 있다.
즉, 여기서 Array는 클래스이며 우리가 사용하던 배열은 이 Array의 인스턴스라는 것을 알 수 있다. 그렇기 때문에 Array 클래스의 prototype에 정의된 배열 메서드들을 배열(인스턴스)에서 사용할 수 있는 것이다.
const array1 = []; // 배열 리터럴로 인스턴스 생성
const array2 = new Array(); // new 키워드로 인스턴스 생성
실세계에 존재하고 인지하고 있는 객체(Object)를 소프트웨어의 세계에서 표현하기 위해 객체의 핵심적인 개념 또는 기능만을 추출하는 추상화(abstraction)를 통해 모델링하려는 프로그래밍 패러다임
객체 지향 프로그래밍은 단순히 별개의 변수와 함수로 순차적으로 작동하는 것을 넘어, 데이터의 접근과, 데이터의 처리 과정에 대한 모형을 만들어 내는 방식을 고안해냈다. 따라서, 데이터와 기능이 별개로 취급되지 않고 한번에 묶어서 처리할 수 있게 되었다.
현대의 언어들(Java, C++, C# 등)은 대부분 객체 지향의 특징을 가지고 있다. 자바스크립트는 엄밀히 말하자면 객체 지향 언어는 아니지만, 객체 지향 패턴으로 작성할 수 있다.
캡슐화는 데이터(속성)와 기능(메서드)을 따로 정의하지 않고, 하나의 단위(객체)로 묶는 것이다. 데이터(속성)와 기능(메서드)이 느슨한 결합을 하는 것이다.
느슨한 결합(Loose Coupling)
: 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아니라, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것을 의미한다.
예를 들면, 마우스 상태를 속성으로, 마우스를 이동하거나 클릭하는 것을 메서드로 정의하는 방식을 느슨한 결합이라고 할 수 있다.
캡슐화는 내부 데이터나 내부 구현이 외부로 노출되지 않도록 하는 은닉화
의 특징도 포함한다. 데이터나 구현은 숨기고, 객체 외부에 필요한 동작(메서드)만 노출시키는 것이다. 객체 내부의 메서드 구현만 수정하고 외부에서 메서드를 사용하는 코드 흐름은 바뀌지 않게 함으로서, 유지 보수를 쉽게 하고 재사용성을 높인다.
추상화는 내부 구현은 복잡한데 실제로 노출되는 부분은 단순하게 만든다는 개념이다.
마우스를 예로 들면, 마우스 내부에 마우스를 작동하게 하는 복잡한 기능들이 있지만 사용자는 이를 신경쓰지 않고 클릭이나 스크롤을 하는 것만으로 마우스를 사용할 수 있다. 추상화를 통해 인터페이스가 단순해지고 너무 많은 기능들이 노출되지 않은 덕분에 예기치 못한 사용상의 변화가 일어나지 않게 할 수 있다.
상속은 부모 클래스의 특징을 자식 클래스가 물려받는 것이다. 기본 클래스(base class)의 특징을 파생 클래스(derived class)가 상속 받는다라고도 표현한다. 부모 클래스의 데이터(속성)와 기능(메서드)를 상속받게 되면, 자식 클래스는 따로 정의하지 않더라도 부모 클래스의 속성과 메서드를 사용할 수 있있다. 이를 통해 불필요한 코드를 줄이고 재사용성을 높일 수 있다.
다형성은 어떤 객체의 속성이나 기능이 상황에 따라 여러 가지 형태를 가질 수 있는 것을 뜻한다.
똑같은 메서드라 하더라도 다른 방식으로 구현될 수 있는 것이다. 예를 들어, 동일한 메서드에 대해 메서드 오버라이딩(overriding)을 통해 재정의함으로써 같은 이름의 메서드가 상황에 따라 다른 역할을 수행하도록 할 수 있다.
참고