1. JS의 class 문법
1function 챔피언(q스킬, w스킬) {2this.q = q스킬3this.w = w스킬4}56const nunu = new 챔피언('잡아먹기', '눈덩이굴리기')7const garen = new 챔피언('돌격', '방패')89console.log('누누: ', nunu)10console.log('가렌": ', garen)
class는 object 뽑는 기계this는 기계로부터 생성되는 object = 인스턴스
위 코드를 ES6 class 문법으로 만들어보면,
1class 챔피언 {2// constructor(생성자) = object 생성 기계3constructor(q스킬, w스킬) {4this.q = q스킬5this.w = w스킬6}7}89const nunu = new 챔피언('잡아먹기', '눈덩이굴리기')10const garen = new 챔피언('돌격', '방패')1112console.log('누누: ', nunu)13console.log('가렌: ', garen)
2. JS의 prototype 문법
1// prototype === 유전자, 자동으로 추가됨2function 챔피언() {3this.q = '잡아먹기'4this.w = '눈덩이굴리기'5}67챔피언.prototype.name = '누누'89let nunu = new 챔피언()1011console.log(nunu.name) // 누누12console.log(nunu) // 챔피언 { q: '잡아먹기', w: '눈덩이굴리기' }
array 자료에 .sort()같은 것들을 붙일 수 있는 이유는? → 부모 유전자에 기록되어 있어서
1let arr = [4, 2, 1]2let arr2 = new Array(4, 2, 1)34arr.sort()5arr2.sort() // [ 1, 2, 4 ]
모든 array 자료에 쓸 수 있는 함수를 추가하려면?
1Array.prototype.추가할함수 = function () {}2let numArr = [4, 2, 1]34numArr.추가할함수()
3. 객체지향 개념
3.1 Imperative and Procedural Programming

명령어과 절차형 프로그래밍
- 객체지향의 반대되는 프로그래밍 패러다임
- 데이터와 함수 위주로 구성하는 것
- 맨 처음 실행되는 main함수
- 그 아래 여러 함수들을 호출 가능
- 함수 내부에서는 전역 변수의 데이터에 접근 가능
- 대표적인 언어 : C
3.2 Object Oriented Programming

객체지향 프로그래밍
- 프로그램을 객체(Object)로 정의해서 객체들끼리 의사소통하고 디자인하고 코딩해나가는 패러다임
- Object 단위로 만들기 떄문에 한 곳에서 문제가 생긴다면, 관련 Object만 수정하면 됨
- 여러 번 반복되는 곳이 있다면, 관련 Object를 재사용할 수 있음
- 무언가 새로운 기능이 필요하다면, 새로운 Object를 만들면 되서 확장성도 높음
- 장점 : 생상성 높음, 높은 퀄리티 프로그램 작성 가능, 빠르게 기능 구현 가능, 유지보수성 향상
객체(object)는 속성(data)과 함수(행동)으로 구성됨
- e.g. MediaPlay(음악 플레이어)
- 속성(data)
- music (음악 데이터)
- 함수(function)
- play(재생 기능)
- stop(정지 기능)
- 속성(data)
속성은 다른 말로fields, property라고도 부름함수는 다른 말로methods라고 부름object를 정의하는 건 프로그래밍 언어마다 다르지만, 보통class라고 부름
class(템플릿, 틀)
- e.g. 붕어빵 만들기
- class === 붕어빵 틀
- object === 팥 붕어빵, 크림 붕어빵, …
- e.g. 학생(student)
- class === 학생 틀
- object === 메시 학생, 호날두 학생
- property === 학생 이름, 성적
- method === 공부하다
4. 객체지향 원칙 4가지
Encapsulation(캡슐화)Abstraction(추상화)Inheritance(상속성): 상속을 이용해 코드 재사용성 높임Polymorphism(다형성): 캡슐화, 추상황, 상속성을 이용해 구현
4.1 Encapsulation(캡슐화)
- 절자지향 프로그래밍에서는 데이터와 함수 등이 여러가지가 섞여있음
- 흩어져 있는 데이터와 함수들 중에 연관있고, 관련있는 것끼리 묶어 놓는 것을
캡슐화라고 함 - e.g. 감기 캡슐약 안에 여러 성분들
- 어떤 성분이 들어있는지 몰라도, 일반인들은 감기약을 먹으면, 감기가 호전된다는 것을 인식함
- 외부에서 보일 필요가 없는 데이터를 잘 숨겨놓음으로써 캡슐화 가능
3.2 Abstraction(추상화)
- 내부에 복잡한 기능을 모르고 다 이해하지 못해도,
- 외부에서 간단한 Interface를 통해서 쓸 수 있는 것을
추상화라고 함 - e.g. 커피머신 작동원리
- 커피머신이 어떻게 내부 동작을 몰라도, 커피 타먹을 수 있음
- 외부에서는 내부가 어떻게 구현되어 있는지 신경쓰지 않고,
- 지정된 외부에 보여줄 함수(Interface)를 통해 객체를 사용 가능
3.3 Inheritance(상속성)
- e.g. 커피 머신이라는 class가 정의되어져 있음
- 상속을 이용해 잘 만들어진 커피머신의 데이터와 함수를 그대로 갖고 와서,
- 필요한 기능을 더해서 다른 종류의 새로운 커피 머신을 만들 수 있음
부모 class를parent, super, base class라고 부르기도 함자식 class를child, sub, derived class라고 부르기도 함- 이 관계를
IS-A관계라고도 부름- e.g. espresso machin is a coffee machine
- e.g. coffee brewer is a coffee machine
다른 상속 예
- 개 is a 동물
- 고양이 is a 동물
- 돼지 is a 동물
다른 상속 예
- HTMLElement is a Element
- Element is a Node
- Node is a EventTarget
- 즉, Document, Element, Text는 모두 EventTarget을 상속받기 때문에, 모든 요소들이 이벤트가 발생할 수 있는 것임
extends 키워드를 사용해서 상속을 구현함
3.3.1 상속의 문제점
- 족보가 꼬인다는 말처럼, 상속이 깊어질 수록 서로 간의 관계가 복잡해짐
- 상속은 수직적인 구조를 짜는 것을 의미합니다.
- 상속의 치명적 문제점은 어떤 부모 클래스의 행동을 수정하게 되면, 이를 상속받는 모든 자식 클래스에도 영향을 미침
- 더군다나 TS에서는 1가지 이상 부모 클래스를 상속받을 수 없음
3.3.2 Composition
레고를 할 때, 필요한 부품을 모아서 조립하는 것처럼, 상속보다 Composition을 선호하셈
- cf. React에서도 상속을 이용한 class 컴포넌트 방식보다는
- Composition 방식의 함수형 컴포넌트를 권장함
3.4 Polymorphism(다형성)
- cf.
poly (=many)|morphi (=form) polymorhism = 다양한 형태- e.g. 어떤 종류의 동물이든 소리를 내는 함수(makeSound())를 가짐
- e.g. makeCoffee()라는 함수만 알면 어떤 종류의 커피머신이든, 커피 만들 수 있음
4. 필드값 타입지정
class 내부에는 모든 자식 object들이 사용가능한 속성을 만들 수 있습니다. 예를 들어, 모든 Person 클래스의 자식들에게 data라는 속성을 부여해주고 싶으면,
1class Person {2// class 중괄호 안에다가 변수처럼 만들면 됨 (let, const 키워드 X)3// class 안에 만드는 속성을 필드(field)라고 부름4data: number = 05}67// Person이 모든 자식에게 data = 0을 하나씩 복사해줌8let john = new Person()9let kim = new Person()1011console.log(john.data)12console.log(kim.data)
5. constructor 타입지정
1// class === object 복사기계2class Person {3constructor() {4// 'this.뭐시기'를 쓰려면 필드값을 만들어줘야 함5this.name = 'kim'6this.age = 207// error TS2339: Property 'age' does not exist on type 'Person'.8}9}
필드 값으로 name, age가 미리 정의되어있어야 constructor 안에서도 사용가능합니다.
1class Person {2// 필드 값이 정의되어 있어야 함3name4age5constructor(a: string) {6this.name = a // 'hello'라는 값이 this.name에 들어감7this.age = 208}9}1011new Person('hello')
생산되는 object마다 각각 다른 이름을 부여하고 싶을 때 유용합니다.
6. methods 타입지정
class 내부엔 함수를 입력할 수 있습니다.
1class Person {2// Person클래스의 prototype에 추가3// 모든 Person의 자식들은 add 라는 함수를 이용가능4add(숫자: number) {5console.log(숫자 + 1)6}7}
6.1 문제
{ model : '소나타', price : 3000 }object를 복사해주는 class 만들기- 복사된 object 자료들은
tax()라는 함수로 현재 object에 저장된 price의 10분의1을 출력
동작 예
1let car1 = new Car('소나타', 3000)2console.log(car1) // { model : '소나타', price : 3000 }3console.log(car1.tax()) // 300
6.2 정답
1class Car {2model: string3price: number4constructor(a: string, b: number) {5this.model = a6this.price = b7}89tax(): number {10return this.price * 0.111}12}1314let car1 = new Car('소나타', 3000)15console.log(car1) // { model : '소나타', price : 3000 }16console.log(car1.tax()) // 300
7. 상속 구현하려면 extends
1class User {2x = 103}45class NewUser extends User {6// User 클래스의 기능들 복붙해줌7}
새로운 NewUser class 만들 때, User에 있는 기능을 상속받아서 사용할 수 있습니다. 비슷한 class를 많이 만들 때, 사용합니다.
8. 접근제한자
접근 제한자를 선언한 속성과 메소드에 대한 접근 가능성은 다음과 같습니다.
| 접근 가능성 | public | protected | private |
|---|---|---|---|
| 클래스 내부 | ◯ | ◯ | ◯ |
| 자식 클래스 내부 | ◯ | ◯ | ✕ |
| 클래스 인스턴스 | ◯ | ✕ | ✕ |
8.1 public
- public이 붙은 속성은 자식 object들이 마음대로 사용하고 수정 가능
- 필드값 같은걸 그냥 만들면 public이 기본값임
- cf. public 키워드는 class 내의 prototype 함수에도 붙일 수 있음
1class User {2// 자식 클래스나 클래스 인스턴스에서 접근 가능3public name: string45constructor() {6this.name = 'kim'7}8}910let 유저1 = new User()11유저1.name = 'park'
8.2 private
- private 키워드를 붙이면 자식 object들이 수정 불가능
- class 중괄호 안에서만 수정 및 사용가능
- cf. 바닐라 JS에서도 속성옆에 # 붙이면 private 속성이 됨
1class User {2public name: string3// 해당 클래스 이외의 위치에서는 접근 불가능4private familyName: string56constructor() {7this.name = 'kim'8let hello = this.familyName + '안뇽' // 가능9}10}1112let 유저1 = new User()13유저1.name = 'park' // public 가능14유저1.familyName = 456 // private라 접근 불가 에러
- cf. class 내의 함수에도 붙일 수 있음
- private 부여된 속성을 class 밖에서 수정해야할 경우
- private 속성을 수정하는 함수를 class 안에 만들어서 함수로 실행
8.2.1 private 속성을 바깥에서 수정
1class Person {2public name: string3private familyName: string // private 속성45constructor() {6this.name = '메시'7this.familyName = 'kim'8}9// private 속성을 바깥에서 수정하려면,10// private 속성을 수정하는 함수를 class 안에서 만들어야 함11// class 바깥에서 함수를 이용하면 간접적으로 수정가능12changeSecret(lastName: string) {13this.familyName = lastName14}15}1617let 집안 = new Person()18console.log(집안)19// 유저1.familyName = 'park'; // 그냥 private 속성을 수정하려면 에러남20집안.changeSecret('park')21console.log(집안)
외부에서 실수로 수정하면, 안되는 속성들은 private를 붙이면 됩니다. private 속성을 수정하려면, 매번 함수를 만들어서 수정해야하니 약간의 안전장치를 더해서 개발이 가능합니다. 이렇게 하면 버그를 예방할 수 있스빈다.
8.2.2 public, private 생략
public, private 키워드를 쓰면, constructor 안에서 this.name = name 이런걸 생략할 수 있습니다.
1class Person {2name3constructor(name: string) {4this.name = name5}6}7let 사람1 = new Person('john')
위 코드와 아래 코드는 같은 역할을 하는 코드입니다.
1class Person {2constructor(public name: string) {}3}4let 사람1 = new Person('john')
8.3 protected
- protected 키워드를 붙이면, 자식 class까지 사용 가능
- extends 된 class 안에서도 사용가능하게 약간 보안을 풀어줌
1class User {2// protected3// - private와 동일하게 class 안에서만 사용이 가능4// - User의 자식들도 함부로 사용이 불가능5protected x = 106}78class NewUser extends User {9// x 속성이 private라면 접근 불가능10// x 속성이 protected라면 접근 가능11doThis() {12this.x = 2013}14}
- class 여러개 만들 때 class 끼리 공유할 수 있는 속성을 만들고 싶으면
protected - class 하나 안에서만 쓸 수 있는 속성을 만들고 싶으면
private
8.4 static 제한자
- static 제한자를 붙이면, 자식에게 물려주지 않음
클래스 안에 있는 변수와 함수는 모두 클래스로부터 새로 생성되는 **object(a.k.a. 인스턴스)**에 부여됩니다.- class로부터 생성되는 object가 사용할 필요가 없는 변수들을 만들어놓고 싶을 때 사용
- 하나의 클래스에 하나만 적용됨
1class User {2// x와 y는 User로 생성된 object들만 사용가능3x = 104y = 205}67let john = new User()8john.x // 가능9User.x // 불가능
class에 직접 변수나 함수를 부여하고 싶으면, static 키워드를 왼쪽에 붙여주면 됩니다.
1class User {2static x = 10 // static을 쓰면 자식에게 안물려줌3y = 204}56let john = new User()7john.x // 불가능8User.x // 가능
- cf. 함수도 static 붙이기 가능
- extends로 class를 복사할 경우 static 붙은 것들도 따라옴
- cf.
static은 private, protected, public 키워드와 동시 사용가능
8.4.1 예시
1class User {2static skill = 'js'3intro = User.skill + '전문가입니다'4}56const 철수 = new User()7console.log(철수) // User { intro: 'js전문가입니다' }89User.skill = 'python' // python으로 수정1011const 민수 = new User()12console.log(민수) // User { intro: 'python전문가입니다' }
class 내부의 기본 변수같은걸 저렇게 수정할 일은 별로 없습니다. 수정하고 싶으면 private 쓰고, 그 다음에 수정함수를 만들어서 사용하는게 더 안전한 방법입니다.
8.5 접근제한자 예시
8.5.1 예시 1
1class User {2// static가 붙으면 자식들은 사용 불가능3private static x = 10 // class 내부에서만 수정가능4public static y = 20 // class 내부 외부 상관없이 수정가능56protected z = 307// private 키워드와 유사하게 class 내부에서만 사용 가능8// extends로 복사한 class 내부에서도 사용 가능9}
8.5.2 예시 2
1class User {2private static x = 103public static y = 2045// static은 class에 직접 부여되는 속성6// static 속성을 수정하거나 가져다 쓰고 싶으면, '클래스명.속성명'7static addOne(파라미터: number) {8User.x += 파라미터9}1011static printX() {12console.log(User.x)13}14}15User.addOne(3)16User.addOne(10)17User.printX() // 23
9. 추상 클래스 : abstract
클래스 앞에 abstract를 붙이면,
- 새로운 인스턴스를 만들 수 없고,
- 반드시 상속을 통해서만 사용할 수 있습니다.
추상 클래스 내부의 메서드에도 abstract를 붙일 수 있습니다
- 상속받은 클래스에서 반드시 추상 메서드의 내용을 만들어야만 정상 동작함
- 단순히 이름만 선언해주고 구체적인 기능은 상속받은 쪽에서 만들어주는 것
1// 추상 class2abstract class Car {3color: string4constructor(color: string) {5this.color = this.color6}7start() {8console.log('시작')9}10abstract doSomething(): void // 추상 메서드 내부의 메서드11}1213// 💥 Error : 'Car' 클래스에서 상속된 추상 멤버 'doSomething'을(를) 구현하지 않습니다14class BMW extends Car {15constructor(color: string) {16super(color)17}18}
상속받은 쪽에서 doSomething 메서드를 선언해야 합니다.
1abstract class Car {2color: string3constructor(color: string) {4this.color = this.color5}6start() {7console.log('시작')8}9abstract doSomething(): void // 추상 메서드10}1112// 추상 클래스를 상속받은 자식 클래스13class BMW extends Car {14constructor(color: string) {15super(color)16}17// 상속받은 자식 클래스에서 추상 메서드 기능 구현18doSomething() {19alert(3)20}21}