절차 지향 프로그래밍과는 다르게 데이터와 기능을 한곳에 묶어서 처리. 속성과 메서드가 하나의 "객체"라는 개념에 포함되고, 내장 타입인 object와는 다르게, 클래스(Class)라는 이름으로 부른다.
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
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
// ES5 클래스는 함수로 정의할 수 있다.
function Car (brand, name, color) {
// 인스턴스 생성 시 실행 코드
}
// ES6 클래스는 class 키워드를 사용해 정의한다.
class Car {
constructor(brand, name, color) { // 생성자 함수는 return 값 없음
// 인스턴스 생성 시 실행 코드
}
}
let veyron = new Car('bugatti', 'veyron', 'black')
// ES5
function Car(brand, name, color) {
// 속성 정의
this.brand = brand;
this.name = name;
this.color = color;
}
// 메서드 정의
Car.prototype.refuel = function() { }
// ES6
class Car {
// 속성 정의
constructor(brand, name, color) {
this.brand = brand;
this.name = name;
this.color = color;
}
// 메서드 정의
refuel() { }
}
// 인스턴스에서 속성과 메서드를 사용
let mini = new Car('bmw', 'mini', 'white');
mini.brand; // 'bmw'
mini.refuel(); // mini에 연료를 공급합니다.
절차 지향 프로그래밍 : 순차적인 명령들의 조합으로, 기껏해야 함수로 이동하는 것이 전부였다. (ex. C, 포트란 등)
객체 지향 프로그래밍 : 별개의 변수와 함수로 순차적으로 작동하는 것을 넘어, 데이터의 접근과, 데이터의 처리 과정에 대한 모형을 만들어 내는 방식이다. 데이터와 기능이 별개로 취급되지 않고, 한 번에 묶여서 처리할 수 있게 되었다. (ex. Java, C++, C# 등)
JavaScript는 엄밀해 말해 객체 지향 언어는 아니지만, 객체 지향 패턴으로 작성할 수 있다.
객체로 그룹화 된다.
데이터와 기능이 함께 있다는 원칙에 따라 메서드와 속성이 존재한다.
클래스는 일종의 원형(original form)으로, 객체를 생성하기 위한 아이디어나 청사진이다.
인스턴스는 클래스의 사례이다.
클래스는 객체를 만들기 위한 생성자 함수를 포함한다. 생성자를 통해 클래스에 세부 사항(속성)을 주입한다.
OOP의 4가지 특징 (OOP Basic Concepts)
- 캡슐화(Encapsulation) : 데이터와 기능을 하나의 단위로 묶는 것으로, 구현은 숨기고 동작은 노출시키는 은닉화와 언제든 구현을 수정할 수 있는 느슨한 결합에 유리한 특징이 있다.
은닉화(hiding)
: 내부 데이터나 내부 구현이 외부로 노출되지 않도록 만드는 것느슨한 결합(Loose Coupling)
: 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아니라, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합하는 것
- 상속(Inheritance) : 부모 클래스의 특징을 자식 클래스가 물려받는 것. (기본 클래스(base class)의 특징을 파생 클래스(derived class)가 상속받는다는 표현이 적합하나, 부모/자식을 많이 사용함)
- 추상화(Abstraction) : 내부 구현은 복잡한데 실제 노출되는 부분은 단순하게 만든다는 개념으로, 인터페이스(interface)를 단순화할 수 있다. 캡슐화는 은닉에 포커스가 있다면, 추상화는 필요치 않은 메서드 등의 노출을 줄이고 단순화 하는 것에 포커스가 있다.
- 다형성(Polymorphism) : 다양한 형태를 가질 수 있는 특성. 똑같은 메서드라 하더라도 다른 방식으로 구현될 수 있다. (ex. HTMLElement)
➡️ 복잡성을 줄이고, 재사용성을 높인다. 변화에 대한 영향을 최소화 한다. 객체의 특성에 맞게 작성할 수 있다는 장점!
MS에서 구현한 JavaScript의 슈퍼셋 프로그래밍 언어로 엄격한 문법을 지원한다. (JavaScript의 한계를 보완)
private
키워드(은닉화) 제공 (JavaScript에서는 ES2019부터 #이라는 키워드가 도입. 지원하는 브라우저가 적어 널리 쓰이지 않음)
class Animal {
private name: string;
constructor(theName: string) {
this.name = theName;
}
}
new Animal("Cat").name; // 사용 불가
// Property 'name' is private and only accessible within class 'Animal'.
interface
키워드(추상화) 제공 (JavaScript에서는 존재하지 않는 기능)interface ClockInterface {
currentTime: Date;
setTime(d: Date): void;
}
class Clock implements ClockInterface {
currentTime: Date = new Date();
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) {}
}
Prototypes are the mechanism by which JavaScript objects inherit features from one another
프로토타입은 자바스크립트 객체를 다른 하나로부터 특성을 상속받기 위한 매커니즘이다.
프로토타입은 object 자료형임.
JavaScript에서는 객체를 상속하기 위하여 프로토타입이라는 방식을 사용함. (흔히 프로토타입 기반 언어(prototype-based language)라 불린다.)
프로토타입에 속성을 추가하면 부모만 가지게 되는데, 자식이 해당 속성을 가지고 있지 않으면 부모 속성을 찾아 대체하기 때문에 부모 속성을 사용할 수 있다. 부모가 없다면 부모의 부모..계속 타고 올라감. (prototype chain)
그래서 프로토타입이 뭔데..?
➡️ 부모 객체의 유전자라고 생각하면 이해하기 쉽다.
class Human {
constructor(name, age) { // 생성자에 작성한 속성은 자식이 직접 가짐
this.name = name;
this.age = age;
}
sleep() {
console.log(`${this.name}은 잠에 들었습니다`);
}
}
let kimcoding = new Human('김코딩', 30);
Human.prototype.constructor === Human; // true
// Human 클래스 원형의 생성자 함수는 Human을 가리킨다.
Human.prototype === kimcoding.__proto__; // true
// __proto__는 kimcoding이라는 객체를 생성한 Human 객체의 prototype 객체를 가리킨다.
Human.prototype.sleep === kimcoding.sleep; // true
// Human 클래스의 sleep 메서드는 프로토타입에 있으며, Human 클래스의 인스턴스인 kimcoding에서 kimcoding.sleep으로 사용할 수 있음
Human.prototype.height = 155; // 프로토타입에 속성을 추가하면 부모만 속성을 가짐
let array = [4, 2, 1]; // 사실은 let array = new Array(4, 2, 1); 와 같은 표현이었다.
Array.prototype // 찍어보면 별의별거 다 나옴
.__proto__
__proto__
프로퍼티가 함께 생성됨.Human.prototype.constructor === Human; // true
// Human 클래스 원형의 생성자 함수는 Human을 가리킨다.
Human.prototype === kimcoding.__proto__; // true
// __proto__는 kimcoding이라는 객체를 생성한 Human 객체의 prototype 객체를 가리킨다.
홍삼 게임도 아니고 아~싸 너너 하면서 서로를 지목하는 프로토타입………어질어질 ^^;
그림으로 이해하는게 확실히 편했다.
객체 지향 프로그래밍의 특성 중 상속을 JavaScript에서 구현할 때에는 프로토타입 체인을 사용함
특정 객체의 프로퍼티나 메소드에 접근시 proto가 가리키는 링크를 따라서 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 접근할 수 있음.
모든 프로토타입 체이닝의 종점은 Object.prototype이다.
let div = document.createElement('div');
div.__proto__ // HTMLDivElement
div.__proto__.__proto__ // HTMLElement
div.__proto__.__proto__.__proto__ // Element
div.__proto__.__proto__.__proto__.__proto__ // Node
div.__proto__.__proto__.__proto__.__proto__.__proto__ // EventTarget
div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ // Object
div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__ // null
프로토타입 기반 OOP는 class 기반의 OOP 와 완전히 상반되는 방식이다.
프로토타입 기반 OOP에서 객체 생성은 일반적으로 복사를 통해 이루어진다.
프로토타입은 개별 객체 수준에서 객체를 수정하고 발전시키는 능력은 선험적 분류의 필요성을 줄이고 반복적인 프로그래밍 및 디자인 스타일을 장려한다.
프로토타입 프로그래밍은 일반적으로 분류하지 않고 유사성을 활용하도록 선택한다.
JS 공부는 아무래도 철학 공부같다.....
| 참고자료 |
잘못된 설명은 댓글로 피드백 주시면 저의 성장에 도움이 됩니다! 감사합니다 :)