객체지향 언어: 클래스
객체지향
클래스를 이용하여 사물/물체(object)들을 객체(object)로 정의해서 프로그래밍하는 것이 자연스럽다. 더 편하고 유연한 프로그래밍을 할 수 있다.
개념
클래스는 연관 있는 데이터를 묶어놓는 컨테이너라고 생각하면 된다. 데이터가 들어있지는 않고 데이터를 받을 수 있는 템플릿이다. 즉, 클래스는 객체의 틀만 만들어둔 것이고, 이 틀에 데이터를 넣어 찍어낸 객체가 인스턴스이다.
클래스는 정의만 한 것이라 메모리에 올라가지 않는다. 반면, 실제 데이터가 들어간 객체는 메모리에 올라간다.
- 구성 : 속성(field), 함수(method).
- 데이터 클래스 : fields로만 구성된 클래스.
- 캡슐화 : 클래스 안에 내부에서만 보이는 변수와 외부에서도 보이는 변수로 나눔.
사용법
<클래스 선언>
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
speak() {
console.log(this.name + " says 'Hi!'");
}
}
- class 키워드를 이용해서 클래스 만들기
- 클래스명은 대문자로 시작
- constructor() 생성자를 이용해서 객체(인스턴스) 만들 때 필요한 데이터 전달하기
- 전달 받은 데이터를 fields에 할당하거나 메서드에 인자로 넘겨주기
<인스턴스 생성>
const ellie = new Person("Ellie", 20);
- const/let 키워드를 이용해서 변수 선언하기
- new 키워드로 클래스 이용한 객체 할당하기
- constructor()에 전달할 데이터 보내기
게터(getter) & 세터(setter)
게터와 세터를 이용해서 새로운 인스턴스를 생성할 때 실수로 잘못된 데이터를 보내는 것을 방지할 수 있다.
<사용법>
get age() {
return this._age;
}
set age(value) {
if (value < 0) {
throw Error("age cannot be negative");
}
this._age = value;
}
- get 키워드를 이용해서 값(예시에서 this._age)을 반환하고, set 키워드를 이용해서 값을 설정(예시에서 this._age에 value 할당). set은 값을 설정하므로 값(예시에서 value)을 받아와야함.
- 콜스택 에러를 피하기 위해 게터와 세터에서 값을 넣을 field의 변수명에 _(언더바)를 넣어야 함.
<콜스택(call stack) 초과 에러>
constructor(age) {
...
this.age = age;
}
// 에러나는 코드
get age() {
return this.age;
}
set age(value) {
this.age = value < 0 ? 0 : value;
}
- age()라는 게터를 정의하는 순간, constructor() 함수 안의 "this.age"는 게터를 호출함.
- 세터를 정의하는 순간, constructor() 함수 안의 "this.age"를 할당하는 "= age" 부분은 메모리에 값을 할당하는 게 아니라 세터를 호출함.
- 즉, 세터 안에서 전달된 value를 this.age에 할당할 때(this.age = value;)도 메모리의 값을 업데이트하는 게 아니라 다시 세터를 호출함.
- 이 과정이 무한 반복되면서 콜스택이 닫힌다.
따라서 이를 방지하기 위해, 게터와 세터 안에 쓰이는 변수의 이름을 다르게 지어야한다. 보통 _(언더바)를 붙인다. 이때, "this._age"라고 해도 게터와 세터를 사용하기 때문에 "this.age"를 호출하고 값을 할당할 수 있다.
Public & Private
constructor() 생성자 쓰지 않고 필드를 정의하면 퍼블릭 필드로, 외부에서 접근 가능하다. 그런데 앞에 #(해시)를 붙이면 프라이빗 필드가 되어, 클래스 내부에서만 값에 접근할 수 있고 변경할 수 있다.
(너무 최신 기능이라 브라우저 지원이 안돼서 사용하려면 바벨을 이용해야 함.)
Static
클래스 안에 있는 필드와 메서드는 새로운 인스턴스를 만들 때 그대로 복제되어 값만 지정한대로 변경된다. 그런데 인스턴스마다 부여하는 데이터에 상관 없이 클래스가 갖는 고유한 값과 메서드가 필요할 때, static 키워드를 붙이면 된다. 그럼 클래스 자체에 내장된 property로서, 인스턴스(객체)가 아니라 클래스에서 꺼내 쓸 수 있다.
class Family {
static familyName = "Lee";
static printName() {
console.log(Family.familyName);
}
}
Family.familyName;
Family.printName();
모든 인스턴스에 복제되지 않기 때문에 메모리의 사용을 줄일 수 있다.
상속 & 다양성
공통적으로 반복되는 것들을 클래스에 정리하여 그 속성값을 재사용하면 간편하다. 문제가 있을 때 클래스만 수정하면 한번에 다 고칠 수 있기 때문에 유지보수도 쉽다.
class Rectangle extends Shape {
draw() {
super.draw();
console.log("■");
}
}
extends 키워드를 이용해서 기존의 클래스 A로부터 연장된 새로운 클래스 B를 만들 수도 있다. 그럼 A의 모든 fields와 methods가 B에 포함된다. 이것을 상속이라고 한다.
연장된 새로운 클래스에서 기존 클래스의 내용을 수정하여 다양성을 발휘할 수 있다. 수정이 필요한 함수들만 override 하면 된다. 그런데 기존의 함수도 두고 다른 코드도 추가하고 싶다면, super.함수();로 부모의 함수를 호출할 수 있다.
instanceOf
instanceOne instanceof Rectangle; 하면 instanceOne 객체가 Rectangle 클래스의 인스턴스인지 확인할 수 있다. 실행하면 true/false를 반환한다. 클래스 A를 상속한 클래스 B의 인스턴스는 A의 인스턴스이다.
같은 원리로, 자바스크립트에서 만든 모든 오브젝트 클래스는 자바스크립트에 내장된 Object(클래스)를 상속한 것이므로, 모든 인스턴스는 Object의 인스턴스이다. 그래서 모든 객체가 toString(), valueOf() 등 Object의 메서드를 사용할 수 있다. 이런 공통 메서드들도 override해서 필요한대로 수정할 수 있다.
참고
[출처] 자바스크립트 6. 클래스와 오브젝트의 차이점(class vs object), 객체지향 언어 클래스 정리 | 프론트엔드 개발자 입문편 (JavaScript ES6) https://www.youtube.com/watch?v=_DLhUBWsRtw
자바 스크립트 참조 - 자바 스크립트 | MDN (mozilla.org)
추가 공부
this.callback && this.callback(this.counter); 는 this.callback이 존재할 때 this.callbakc(this.counter) 실행.
js 파일 최상단에 'use strict'
프로토타입 베이스 inheritance
this._age = value < 0 ? 0 : value; 는 value가 0보다 작을 때 0을, 아닐 때 value을 할당한다.
'TIL' 카테고리의 다른 글
[TIL-114] 위코드 13일차: enemyRain 게임 - 내려오는 유령 (0) | 2022.02.05 |
---|---|
[TIL-113] 위코드 12일차: enemyRain 게임 - 배경 이미지와 캐릭터 이동 (0) | 2022.02.04 |
[TIL-111] 노마드코더 그림판(JS) 클론코딩 #2.4~#2.7 (완강) (0) | 2022.02.02 |
[TIL-110] 노마드코더 그림판(JS) 클론코딩 #1.0~#2.3 (0) | 2022.02.01 |
[TIL-109] 위코드 8일차: JS replit 27~33 "ES6 추가 기능", "DOM" (0) | 2022.01.31 |