Object-Oriented Programming
하나의 모델이 되는 청사진(blueprint)을 만들고 (Class),그 청사진을 바탕으로 한 객체를(object) 만드는 (instance) 프로그래밍 패턴
- 속성과 메소드가 하나의 "객체"라는 개념에 포함
*자바스크립트 내장 타입인 object(이하, obj literal)와는 다르게 Class라는 이름 사용 - instance : 청사진을 바탕으로 만들어진 인스턴트 객체 (instance object)
- 절차 지향 프로그래밍과 달리 데이터와 기능을 한곳에 묶어서 처리
*절차적 언어 : 순차적인 명령의 조합 - 자바스크립트 : 객체 지향 언어는 아니지만 객체 지향 패턴으로 작성 가능
OOP의 특징
1. 캡슐화(Encapsulation)
- 데이터(속성)와 기능(메소드)을 하나의 단위로 묶는 것
- 코드가 복잡하지 않고 재사용 가능하도록 만들어줌
1-1. 은닉(hiding)
const Monkey = function(name) {
this.name = name
}
const Ukkikki = new Monkey('Ukkikki')
Ukkikki.name = 'Despair'
console.log(Ukkikki)
// Monkey {name: "Despair"}
// Ukkikki의 이름이 "Despair"로 바뀜
- 은닉화 : 구현은 숨기고 객체 외부에서 필요한 동작(메소드)만 노출시켜 내부 데이터나 내부 구현이 외부로 노출되지 않도록 함
- 엄격한 클래스 : 속성의 직접적인 접근을 막고, 설정하는 함수(setter)와 불러오는 함수(getter)를 철저하게 구분하기도 함
const Monkey = function(name) {
const a = name
this.getName = function() {
console.log(a)
}
}
const Ukkikki = new Monkey('Ukkikki')
Ukkikki.name = 'Despair'
console.log(Ukkikki)
//Monkey {name: "Despair", getName: ƒ}
Ukkikki.getName()
//Ukkikki
//외부에선 값을 얻을 수만 있고 바꿀 순 없음
- 클로저를 활용한 방법
class Monkey {
#name
constructor(name) {
this.#name = name
}
}
const Ukkikki = new Monkey('Ukkikki')
Ukkikki.#name = 'Despair'
//에러 발생 : Private field '#name' must be declared in an enclosing class
- #키워드를 사용한 방법(only class) : #name
1-2. 느슨한 결합(Loose Coupling)에 유리
- 언제든 구현 수정 가능
- 느슨한 결합 : 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아닌, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합
2. 추상화(Abstraction)
- 내부 구현은 복잡하지만 실제로 노출되는 부분은 단순하게 만드는 것
- 단순한 인터페이스 : 너무 많은 기능들이 노출되지 않아 예기치 못한 사용상 변화 방지
3. 상속(Inheritance)
- 부모 클래스의 특징을 자식 클래스가 물려받는 것
*기본 클래스(base class)의 특징을 파생 클래스(derive class)가 상속받는 것 - 자식 클래스만의 특징 : 추가적으로 속성/메소드 추가 가능
4. 다형성(Polymorphism)
- 다양한 형태를 가질 수 있는 특징 : 똑같은 메소드라도 다른 방식으로 구현 가능
클래스를 이용한 모듈화
1. 객체
- 속성(property): 키-값 쌍을 의미
- 메소드 호출 : 객체.메소드()
*화살표 함수 사용 불가
2. 클래스
2-1. ES6
class Monkey {
// 생성자(constructor) 함수
constructor(name, color, age) { // 속성
this.name = name
this.color = color
this.age = age
}
sayHello() { // 메소드
return `Hello, I'am ${this.name}`
}
}
console.log(Monkey.prototype)
// {constructor: ƒ, sayHello: ƒ}
// constructor: class Monkey
// sayHello: ƒ sayHello()
// __proto__: Object
const Ukkikki = new Monkey('Ukkikki', 'Black', 7)
console.log(Ukkikki)
// Monkey {name: "Ukkikki", color: "Black", age: 7}
// age: 7
// color: "Black"
// name: "Ukkikki"
// __proto__:
// constructor: class Monkey
// sayHello: ƒ sayHello()
// __proto__: Object
for(key in Ukkikki) {
console.log(key)
}
// name, color, age
// 메소드는 제외됨
- 하나의 모델이 되는 청사진(blueprint)
- 클래스명 : 대문자로 시작하는 일반명사
*일반 함수 : 적절한 동사를 포힘, 소문자로 시작 - 속성 : name, color, age
- 생성자(constructor) 함수 : 인스턴스가 만들어질 때 실행되는 코드로 return 값을 만들지 않음
*this : 인스턴스 객체를 의미 - 메소드 : 객체에 딸린 함수를 의미, 생성자 함수와 함께 class 키워드 안쪽에 묶어서 정의
2-2. ES5
// 생성자(constructor) 함수
function Monkey(name, color, age) { // 속성
this.name = name
this.color = color
this.age = age
this.eat = function() {
console.log('eating...')
}
}
Monkey.prototype.legs = 4
Monkey.prototype.sayHello = function() { // 메소드
return `Hello, I'am ${this.name}`
}
// 위의 코드는 아래처럼도 가능하지만 아래의 경우 constructor 명시 필요
// Monkey.prototype = {
// constructor : Monkey,
// legs = 4,
// sayHello = function() { // 메소드
// return `Hello, i'am ${this.name}`
// }
// }
console.log(Monkey.prototype)
// {legs: 4, sayHello: ƒ, constructor: ƒ}
// legs: 4
// sayHello: ƒ ()
// constructor: ƒ Monkey(name, color, age)
// __proto__: Object
const Ukkikki = new Monkey('Ukkikki', 'Black', 7)
console.log(Ukkikki)
// Monkey {name: "Ukkikki", color: "Black", age: 7, eat: ƒ}
// age: 7
// color: "Black"
// eat: ƒ ()
// name: "Ukkikki"
// __proto__:
// legs: 4
// sayHello: ƒ ()
// constructor: ƒ Monkey(name, color, age)
// __proto__: Object
- prototype 키워드를 사용해 프로토타입에 저장 가능
3. 인스턴스
let Ukkikki = new Monkey('Ukkikki', 'Black', 7)
Ukkikki.color // Black
Ukkikki.age // 7
Ukkikki.sayHello() // Hello, i'am Ukkikki
- 청사진(blueprint)을 바탕으로 만든 객체
- 인스턴스 만들기 : new 키워드 사용
- 생성자 함수가 실행되며 변수에 클래스의 설계를 닮은 새로운 객체(인스턴스) 생성
- 인스턴스 : 고유한 속성과 메소드를 갖게 됨
Prototype
const Monkey = {
legs: 4,
sleep() {
console.log("slepping...")
}
}
const Ukkikki = {
name : "Ukkikki",
color : "Black"
}
Ukkikki.__proto__ = Monkey
console.log(Ukkikki.legs) //4
// Ukkikki 객체엔 legs가 없지만 __proto__로 Monkey을 상속받음
// Ukkikki.legs : Ukkikki 객체에 legs가 없으므로 __proto__에서 legs를 찾음
for (key in Ukkikki) {
console.log(key)
}
// name, color, legs, sleep
// 상속받은 key까지 모두 나옴
// .hasOwnProperty를 이용하면 for in 문에서도 상속된 property는 나오지 않게 할 수 있음
Object.keys(Ukkikki) // ["Ukkikki", "Black"]
Object.values(Ukkikki) // ["Ukkikki", "Black"]
// 상속된 property는 나오지 않음
const Ukkikki2 = {
name : "Ukkikki2",
color : "gray"
}
Ukkikki2.__proto__ = Ukkikki
console.log(Ukkikki2.legs) //4
// 상속은 계속됨
// legs가 Ukkikki에 없어 Ukkikki로 올라가 찾고,
// Ukkikki에도 없으면 Monkey으로 올라가 찾음 = Prototype Chain
const Ukkikki = {
name : "Ukkikki",
color : "Black",
legs : 5
}
console.log(Ukkikki.legs) //5
// Ukkikki.legs : Ukkikki 객체에 legs있으므로 Ukkikki 객체에서 legs를 찾음
- JavaScript : 프로토타입 기반 언어로, 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가짐
- 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지(= 프로토타입 체인)
- 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있는 것
- 프로토타입 : 모델의 청사진을 만들 때 쓰는 원형 객체(original form)
1. 클래스와 프로토타입
Monkey.prototype.constructor === Monkey // true
Monkey.prototype === Ukkikki.__proto__ // true
Monkey.prototype.sayHello === Ukkikki.sayHello // true
![[JavaScript] 객체 지향 프로그래밍 - Prototype - 1. 클래스와 프로토타입 [JavaScript] 객체 지향 프로그래밍 - Prototype - 1. 클래스와 프로토타입](https://blog.kakaocdn.net/dn/cmJw9i/btruAsOiftw/1BRIbuoRBvWIVho175bOK0/img.jpg)
- Monkey의 prototype의 생성자는 Monkey
- Monkey의 prototype엔 sayHello가 존재
- Ukkikki.sayHello는 Monkey.prototype.sayHello를 '언더 proto'로 참조
- new Monkey을 통해 Ukkikki 인스턴스 생성
2. 프로토타입 체인
- 프로토타입 체인(prototype chain) : 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 해줌
- 상속 : 자바스크립트에서 구현할 때 프로토타입 체인 사용
*extends와 super 키워드를 이용 - extends : 상속할 때 사용
- super :
- 자식 클래스에 constructor를 쓰고 싶을 때 사용
- 자식 메소드에 부모의 메소드와 동일한 이름의 메소드가 있는 경우 부모의 메소드를 그대로 쓰면서 확장하고 싶을 때 사용
class Person {
constructor(name) {
this.name = name
}
sleep() {
console.log('sleeping...')
}
}
const Nightmarish = new Person('Nightmarish')
class Student extends Person{
constructor(name, age) {
super(name)
// super 키워드가 없으면 에러 발생
// super를 통해 먼저 부모의 constructor를 실행해줘야 함
// 이때 인자도 받아서 넘겨줘야 함
this.age = age
}
sleep() {
super.sleep()
// super 키워드가 없으면 자식 메소드로 덮어씌워져 'zzz...'만 나옴
// super 키워드 사용 시 부모의 메소드 사용으로 'sleeping...'도 나옴
console.log('zzz...')
}
learn() {
console.log('learning...')
}
}
const Despair = new Student('Despair', 16)
console.log(Despair)
// Student {name: "Despair", age: 16}
// age: 16
// name: "Despair"
// __proto__: Person
// constructor: class Student
// learn: ƒ learn()
// sleep: ƒ sleep()
// __proto__:
// constructor: class Person
// sleep: ƒ sleep()
// __proto__: Object
Despair.name // 'Despair'
Despair.learn() // 'learning...'
Despair.sleep() // 'sleeping...', 'zzz...'
Despair instanceof Student // true
Despair instanceof Person // true
Despair.__proto__ // Person
References
반응형
'CodeStates > JavaScript' 카테고리의 다른 글
[JSON] JavaScript Object Notation (1) | 2022.03.14 |
---|---|
[JavaScript] 재귀함수 (1) | 2022.03.14 |
[JavaScript] 고차함수 (0) | 2022.02.27 |
[JavaScript] 원시 자료형과 참조 자료형 (0) | 2022.02.09 |
[JavaScript] 호이스팅 (0) | 2022.01.21 |
댓글