[JS] 객체 지향 프로그래밍(OOP)의 기초
29957 단어 JavaScript코드스테이츠JavaScript
객체 지향 프로그래밍
1. 개념
- 하나의 모델이 되는 청사진(blueprint)을 만들고, 그 청사진을 바탕으로 한 객체를 만드는 프로그래밍 패턴
- 절차 지향 프로그래밍과 달리 데이터와 기능을 한곳에 묶어서 처리
*절차적 언어 : 순차적인 명령의 조합
- 속성과 메소드가 하나의 '객체'라는 개념에 포함
*자바스크립트 내장 타입인 object와는 달리 Class라는 이름 사용
- 자바스크립트 : 객체 지향 언어는 아니지만 객체 지향 패턴으로 작성 가능
2. 특징
1) 캡슐화(Encapsulation)
- 데이터(속성)와 기능(메소드)을 하나의 단위로 묶는 것
- 코드가 복잡하지 않고 재사용 가능하도록 만들어줌
(1) 은닉(hiding)
- 은닉화 : 구현은 숨기고 객체 외부에서 필요한 동작(메소드)만 노출시켜 내부 데이터나 내부 구현이 외부로 노출되지 않도록 함
- 엄격한 클래스 : 속성의 직접적인 접근을 막고, 설정하는 함수(setter)와 불러오는 함수(getter)를 철저하게 구분하기도 함
const Cat = function(name) {
this.name = name
}
const KKAKKA = new Cat('KKAKKA')
KKAKKA.name = 'GGAGGA'
console.log(KKAKKA)
// Cat {name: "GGAGGA"}
// KKAKKA의 이름이 GGAGGA로 바뀜
- 클로저를 활용한 방법
const Cat = function(name) {
const a = name
this.getName = function() {
console.log(a)
}
}
const KKAKKA = new Cat('KKAKKA')
KKAKKA.name = 'GGAGGA'
console.log(KKAKKA)
// Cat {name: "GGAGGA", getName: ƒ}
KKAKKA.getName()
// KKAKKA
// 외부에선 값을 얻을 수만 있고 바꿀 순 없음
- #키워드를 사용한 방법(only class) : #name
class Cat {
#name
constructor(name) {
this.#name = name
}
}
const KKAKKA = new Cat('KKAKKA')
KKAKKA.#name = 'GGAGGA'
//에러 발생 : Private field '#name' must be declared in an enclosing class
(2) 느슨한 결합(Loose Coupling)에 유리
- 언제든 구현 수정 가능
- 느슨한 결합 : 코드 실행 순서에 따라 절차적으로 코드를 작성하는 것이 아닌, 코드가 상징하는 실제 모습과 닮게 코드를 모아 결합
2) 추상화(Abstraction)
- 내부 구현은 복잡하지만 실제로 노출되는 부분은 단순하게 만드는 것
- 단순한 인터페이스 : 너무 많은 기능들이 노출되지 않아 예기치 못한 사용상 변화 방지
3) 상속(Inheritance)
- 부모 클래스의 특징을 자식 클래스가 물려받는 것
*기본 클래스(base class)의 특징을 파생 클래스(derive class)가 상속받는 것
- 자식 클래스만의 특징 : 추가적으로 속성/메소드 추가 가능
4) 다형성(Polymorphism)
- 다양한 형태를 가질 수 있는 특징 : 똑같은 메소드라도 다른 방식으로 구현 가능
클래스를 이용한 모듈화
1. 객체
- 속성(property): 키-값 쌍을 의미
- 메소드 호출 : 객체.메소드()
*화살표 함수 사용 불가
2. 클래스
1) ES6
class Cat {
// 생성자(constructor) 함수
constructor(name, color, age) { // 속성
this.name = name
this.color = color
this.age = age
}
sayHello() { // 메소드
return `Hello, I'am ${this.name}`
}
}
console.log(Cat.prototype)
// {constructor: ƒ, sayHello: ƒ}
// constructor: class Cat
// sayHello: ƒ sayHello()
// __proto__: Object
const KKAKKA = new Cat('KKAKKA', 'Black', 7)
console.log(KKAKKA)
// Cat {name: "KKAKKA", color: "Black", age: 7}
// age: 7
// color: "Black"
// name: "KKAKKA"
// __proto__:
// constructor: class Cat
// sayHello: ƒ sayHello()
// __proto__: Object
for(key in KKAKKA) {
console.log(key)
}
// name, color, age
// 메소드는 제외됨
- 하나의 모델이 되는 청사진(blueprint)
- 클래스명 : 대문자로 시작하는 일반명사
*일반 함수 : 적절한 동사를 포힘, 소문자로 시작
- 속성 : name, color, age
- 생성자(constructor) 함수 : 인스턴스가 만들어질 때 실행되는 코드로 return 값을 만들지 않음
*this : 인스턴스 객체를 의미
- 메소드 : 객체에 딸린 함수를 의미, 생성자 함수와 함께 class 키워드 안쪽에 묶어서 정의
2) ES5
// 생성자(constructor) 함수
function Cat(name, color, age) { // 속성
this.name = name
this.color = color
this.age = age
this.eat = function() {
console.log('eating...')
}
}
Cat.prototype.legs = 4
Cat.prototype.sayHello = function() { // 메소드
return `Hello, I'am ${this.name}`
}
// 위의 코드는 아래처럼도 가능하지만 아래의 경우 constructor 명시 필요
// Cat.prototype = {
// constructor : Cat,
// legs = 4,
// sayHello = function() { // 메소드
// return `Hello, i'am ${this.name}`
// }
// }
console.log(Cat.prototype)
// {legs: 4, sayHello: ƒ, constructor: ƒ}
// legs: 4
// sayHello: ƒ ()
// constructor: ƒ Cat(name, color, age)
// __proto__: Object
const KKAKKA = new Cat('KKAKKA', 'Black', 7)
console.log(KKAKKA)
// Cat {name: "KKAKKA", color: "Black", age: 7, eat: ƒ}
// age: 7
// color: "Black"
// eat: ƒ ()
// name: "KKAKKA"
// __proto__:
// legs: 4
// sayHello: ƒ ()
// constructor: ƒ Cat(name, color, age)
// __proto__: Object
- prototype 키워드를 사용해 프로토타입에 저장 가능
3. 인스턴스
let KKAKKA = new Cat('KKAKKA', 'Black', 7)
KKAKKA.color // Black
KKAKKA.age // 7
KKAKKA.sayHello() // Hello, i'am KKAKKA
- 청사진(blueprint)을 바탕으로 만든 객체
- 인스턴스 만들기 : new 키워드 사용
- 생성자 함수가 실핼되며 변수에 클래스의 설계를 닮은 새로운 객체(인스턴스) 생성
- 인스턴스 : 고유한 속성과 메소드를 갖게 됨
Prototype
const Cat = {
legs: 4,
sleep() {
console.log("slepping...")
}
}
const KKAKKA = {
name : "KKAKKA",
color : "Black"
}
KKAKKA.__proto__ = Cat
console.log(KKAKKA.legs) //4
// KKAKKA 객체엔 legs가 없지만 __proto__로 Cat을 상속받음
// KKAKKA.legs : KKAKKA 객체에 legs가 없으므로 __proto__에서 legs를 찾음
for (key in KKAKKA) {
console.log(key)
}
// name, color, legs, sleep
// 상속받은 key까지 모두 나옴
// .hasOwnProperty를 이용하면 for in 문에서도 상속된 property는 나오지 않게 할 수 있음
Object.keys(KKAKKA) // ["KKAKKA", "Black"]
Object.values(KKAKKA) // ["KKAKKA", "Black"]
// 상속된 property는 나오지 않음
const KKAKKA2 = {
name : "KKAKKA2",
color : "gray"
}
KKAKKA2.__proto__ = KKAKKA
console.log(KKAKKA2.legs) //4
// 상속은 계속됨
// legs가 KKAKKA2에 없어 KKAKKA로 올라가 찾고,
// KKAKKA에도 없으면 Cat으로 올라가 찾음 = Prototype Chain
const KKAKKA = {
name : "KKAKKA",
color : "Black",
legs : 5
}
console.log(KKAKKA.legs) //5
// KKAKKA.legs : KKAKKA 객체에 legs있으므로 KKAKKA 객체에서 legs를 찾음
- JavaScript : 프로토타입 기반 언어로, 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가짐
- 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지(= 프로토타입 체인)
- 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있는 것
- 프로토타입 : 모델의 청사진을 만들 때 쓰는 원형 객체(original form)
1. 클래스와 프로토타입
Cat.prototype.constructor === Cat // true
Cat.prototype === KKAKKA.__proto__ // true
Cat.prototype.sayHello === KKAKKA.sayHello // true
*절차적 언어 : 순차적인 명령의 조합
*자바스크립트 내장 타입인 object와는 달리 Class라는 이름 사용
const Cat = function(name) {
this.name = name
}
const KKAKKA = new Cat('KKAKKA')
KKAKKA.name = 'GGAGGA'
console.log(KKAKKA)
// Cat {name: "GGAGGA"}
// KKAKKA의 이름이 GGAGGA로 바뀜
const Cat = function(name) {
const a = name
this.getName = function() {
console.log(a)
}
}
const KKAKKA = new Cat('KKAKKA')
KKAKKA.name = 'GGAGGA'
console.log(KKAKKA)
// Cat {name: "GGAGGA", getName: ƒ}
KKAKKA.getName()
// KKAKKA
// 외부에선 값을 얻을 수만 있고 바꿀 순 없음
class Cat {
#name
constructor(name) {
this.#name = name
}
}
const KKAKKA = new Cat('KKAKKA')
KKAKKA.#name = 'GGAGGA'
//에러 발생 : Private field '#name' must be declared in an enclosing class
*기본 클래스(base class)의 특징을 파생 클래스(derive class)가 상속받는 것
1. 객체
- 속성(property): 키-값 쌍을 의미
- 메소드 호출 : 객체.메소드()
*화살표 함수 사용 불가
2. 클래스
1) ES6
class Cat {
// 생성자(constructor) 함수
constructor(name, color, age) { // 속성
this.name = name
this.color = color
this.age = age
}
sayHello() { // 메소드
return `Hello, I'am ${this.name}`
}
}
console.log(Cat.prototype)
// {constructor: ƒ, sayHello: ƒ}
// constructor: class Cat
// sayHello: ƒ sayHello()
// __proto__: Object
const KKAKKA = new Cat('KKAKKA', 'Black', 7)
console.log(KKAKKA)
// Cat {name: "KKAKKA", color: "Black", age: 7}
// age: 7
// color: "Black"
// name: "KKAKKA"
// __proto__:
// constructor: class Cat
// sayHello: ƒ sayHello()
// __proto__: Object
for(key in KKAKKA) {
console.log(key)
}
// name, color, age
// 메소드는 제외됨
- 하나의 모델이 되는 청사진(blueprint)
- 클래스명 : 대문자로 시작하는 일반명사
*일반 함수 : 적절한 동사를 포힘, 소문자로 시작 - 속성 : name, color, age
- 생성자(constructor) 함수 : 인스턴스가 만들어질 때 실행되는 코드로 return 값을 만들지 않음
*this : 인스턴스 객체를 의미 - 메소드 : 객체에 딸린 함수를 의미, 생성자 함수와 함께 class 키워드 안쪽에 묶어서 정의
2) ES5
// 생성자(constructor) 함수
function Cat(name, color, age) { // 속성
this.name = name
this.color = color
this.age = age
this.eat = function() {
console.log('eating...')
}
}
Cat.prototype.legs = 4
Cat.prototype.sayHello = function() { // 메소드
return `Hello, I'am ${this.name}`
}
// 위의 코드는 아래처럼도 가능하지만 아래의 경우 constructor 명시 필요
// Cat.prototype = {
// constructor : Cat,
// legs = 4,
// sayHello = function() { // 메소드
// return `Hello, i'am ${this.name}`
// }
// }
console.log(Cat.prototype)
// {legs: 4, sayHello: ƒ, constructor: ƒ}
// legs: 4
// sayHello: ƒ ()
// constructor: ƒ Cat(name, color, age)
// __proto__: Object
const KKAKKA = new Cat('KKAKKA', 'Black', 7)
console.log(KKAKKA)
// Cat {name: "KKAKKA", color: "Black", age: 7, eat: ƒ}
// age: 7
// color: "Black"
// eat: ƒ ()
// name: "KKAKKA"
// __proto__:
// legs: 4
// sayHello: ƒ ()
// constructor: ƒ Cat(name, color, age)
// __proto__: Object
- prototype 키워드를 사용해 프로토타입에 저장 가능
3. 인스턴스
let KKAKKA = new Cat('KKAKKA', 'Black', 7)
KKAKKA.color // Black
KKAKKA.age // 7
KKAKKA.sayHello() // Hello, i'am KKAKKA
- 청사진(blueprint)을 바탕으로 만든 객체
- 인스턴스 만들기 : new 키워드 사용
- 생성자 함수가 실핼되며 변수에 클래스의 설계를 닮은 새로운 객체(인스턴스) 생성
- 인스턴스 : 고유한 속성과 메소드를 갖게 됨
Prototype
const Cat = {
legs: 4,
sleep() {
console.log("slepping...")
}
}
const KKAKKA = {
name : "KKAKKA",
color : "Black"
}
KKAKKA.__proto__ = Cat
console.log(KKAKKA.legs) //4
// KKAKKA 객체엔 legs가 없지만 __proto__로 Cat을 상속받음
// KKAKKA.legs : KKAKKA 객체에 legs가 없으므로 __proto__에서 legs를 찾음
for (key in KKAKKA) {
console.log(key)
}
// name, color, legs, sleep
// 상속받은 key까지 모두 나옴
// .hasOwnProperty를 이용하면 for in 문에서도 상속된 property는 나오지 않게 할 수 있음
Object.keys(KKAKKA) // ["KKAKKA", "Black"]
Object.values(KKAKKA) // ["KKAKKA", "Black"]
// 상속된 property는 나오지 않음
const KKAKKA2 = {
name : "KKAKKA2",
color : "gray"
}
KKAKKA2.__proto__ = KKAKKA
console.log(KKAKKA2.legs) //4
// 상속은 계속됨
// legs가 KKAKKA2에 없어 KKAKKA로 올라가 찾고,
// KKAKKA에도 없으면 Cat으로 올라가 찾음 = Prototype Chain
const KKAKKA = {
name : "KKAKKA",
color : "Black",
legs : 5
}
console.log(KKAKKA.legs) //5
// KKAKKA.legs : KKAKKA 객체에 legs있으므로 KKAKKA 객체에서 legs를 찾음
- JavaScript : 프로토타입 기반 언어로, 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가짐
- 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지(= 프로토타입 체인)
- 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있는 것
- 프로토타입 : 모델의 청사진을 만들 때 쓰는 원형 객체(original form)
1. 클래스와 프로토타입
Cat.prototype.constructor === Cat // true
Cat.prototype === KKAKKA.__proto__ // true
Cat.prototype.sayHello === KKAKKA.sayHello // true
const Cat = {
legs: 4,
sleep() {
console.log("slepping...")
}
}
const KKAKKA = {
name : "KKAKKA",
color : "Black"
}
KKAKKA.__proto__ = Cat
console.log(KKAKKA.legs) //4
// KKAKKA 객체엔 legs가 없지만 __proto__로 Cat을 상속받음
// KKAKKA.legs : KKAKKA 객체에 legs가 없으므로 __proto__에서 legs를 찾음
for (key in KKAKKA) {
console.log(key)
}
// name, color, legs, sleep
// 상속받은 key까지 모두 나옴
// .hasOwnProperty를 이용하면 for in 문에서도 상속된 property는 나오지 않게 할 수 있음
Object.keys(KKAKKA) // ["KKAKKA", "Black"]
Object.values(KKAKKA) // ["KKAKKA", "Black"]
// 상속된 property는 나오지 않음
const KKAKKA2 = {
name : "KKAKKA2",
color : "gray"
}
KKAKKA2.__proto__ = KKAKKA
console.log(KKAKKA2.legs) //4
// 상속은 계속됨
// legs가 KKAKKA2에 없어 KKAKKA로 올라가 찾고,
// KKAKKA에도 없으면 Cat으로 올라가 찾음 = Prototype Chain
const KKAKKA = {
name : "KKAKKA",
color : "Black",
legs : 5
}
console.log(KKAKKA.legs) //5
// KKAKKA.legs : KKAKKA 객체에 legs있으므로 KKAKKA 객체에서 legs를 찾음
Cat.prototype.constructor === Cat // true
Cat.prototype === KKAKKA.__proto__ // true
Cat.prototype.sayHello === KKAKKA.sayHello // true
- Cat의 prototype의 생성자는 Cat
- Cat의 prototype엔 sayHello가 존재
- KKAKKA.sayHello는 Cat.prototype.sayHello를 '던더 proto'로 참조
- new Cat을 통해 KKAKKA 인스턴스 생성
2. 프로토타입 체인
- 프로토타입 체인(prototype chain) : 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 해줌
- 상속 : 자바스크립트에서 구현할 때 프로토타입 체인 사용
*extends와 super 키워드를 이용 - extends : 상속할 때 사용
- super :
- 자식 클래스에 constructor를 쓰고 싶을 때 사용
- 자식 메소드에 부모의 메소드와 동일한 이름의 메소드가 있는 경우 부모의 메소드를 그대로 쓰면서 확장하고 싶을 때 사용
class Person {
constructor(name) {
this.name = name
}
sleep() {
console.log('sleeping...')
}
}
const somin = new Person('somin')
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 park = new Student('park', 16)
console.log(park)
// Student {name: "park", age: 16}
// age: 16
// name: "park"
// __proto__: Person
// constructor: class Student
// learn: ƒ learn()
// sleep: ƒ sleep()
// __proto__:
// constructor: class Person
// sleep: ƒ sleep()
// __proto__: Object
park.name // 'Park'
park.learn() // 'learning...'
park.sleep() // 'sleeping...', 'zzz...'
park instanceof Student // true
park instanceof Person // true
park.__proto__ // Person
References
Author And Source
이 문제에 관하여([JS] 객체 지향 프로그래밍(OOP)의 기초), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sominpark/객체-지향-프로그래밍OOP-Object-oriented-programming의-기초저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)