https://youtu.be/_DLhUBWsRtw
드림코딩 by 엘리 님의 유튜브 강의를 보며 정리한 내용입니다.
class 란 조금 더 연관 있는 데이터들을 한데 묶어 놓은 컨테이너 같은 것이다.
class Person {
name; //property *속성(filed)*
age; //property *속성(filed)*
speak(); //funtion *행동(method)*
}
Person 이라는 class
안에는
properties
가 들어 있고 ← field(속성)function
이 들어 있다. ← method(행동)즉, class
는 field 와 method 가 종합적으로 묶여있는 것이며, 간혹 method는 들어있지 않고 데이터(=fields) 만 들어있는 경우도 있는데 이를 data class 라고 부른다.
이렇게 관련 있는 변수나 함수들을 묶어 놓은 것을 class
라고 하고, 이 class안에서도
들을 나누어서 이런 것들을 encapsulation(=캡슐화) 라고 한다.
그리고 class를 이용해서 Inheritance(상속)과 Overriding(다양성)이 일어날 수 있는데, 이런 모든 것들이 가능한 것이 바로 객체지향언어 이다.
붕어빵틀(class
)을 이용해서 팥(date) 을 넣어서 만들면 팥 붙어빵(object
), 크림(data) 을 넣어서 만들면 크림 붕어빵(object
) 이 된다.
이렇게 만들어진 붕어빵 자체는 object 이고, 붕어빵을 만들기 위해 정의한 붕어빵 틀은 class가 되는 것이다.
class는 붕어빵을 만들 수 있는 틀을 말한다. 청사진이라고도 불리고 템플릿이라고도 불린다. class 자체에는 데이터가 들어있지 않고, 틀(템플릿)만 정의해 놓는 것이다. (ex: 이런 class 에는 이런이런 data만 들어올 수 있어) 라고만 정의해 놓고 한 번만 선언한다.
그리고 class를 이용해서 실제로 data를 넣어서 만드는 것이 바로 → Object
class를 이용해서 새로운 인스턴스(instance) 를 생성하면 object가 된다.
object는 class를 이용해서 굉장히 많이 만들 수 있고, 데이터를 넣었으니 메모리에도 올라가게 된다.
(↔ class는 정의만 한 것이라서 실제로 메모리에 올라가지는 않는다.)
//이 class 에는 이름과 나이라는 fields 가 있고, speak 라는 method도 있다.
class Person {
//constructor (생성자)
constructor (name, age) {
//fields
this.name = name;
this.age = age;
}
//methods
speak() {
console.log(`${this.name}: hello!`);
}
}
class
라는 키워드를 이용해서 Person이라는 클래스를 만들고 생성자(constructor)
를 이용해서 나중에 우리가 object를 만들 때 필요한 데이터를 전달한다. 그래서 전달받은 이 데이터를 클래스에 존재하는 두가지의 fields
인 name과 age에 전달된 데이터를 바로 할당해준다.
새로운 Object를 만들 때에는 new 라는 키워드를 쓴다.
//위에서 생성한 class를 이용해 object를 만들어보기
const jane = new Person('jane', 24);
console.log(jane.name); //jane
console.log(jane.age); //24
jane.speak(); //jane: hello!
get
키워드를 이용해서 값을 return하고set
키워드를 이용해서 값을 설정한다.class User {
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
get age() {
return this._age;
}
set age(value) { //set은 값을 설정하게 때문에 value를 받아와야 한다.
if(value < 0){
throw Error('age can not be negative');
}
this._age = value;
}
}
const user1 = new User('steve', 'job', -1);
console.log(user1.age); //-1이 나오는게 아니고 setter에서 설정한 경고가 뜬다.
//이렇게 사람의 나이가 마이너스인 것은 말이 안되는 것처럼, class를 잘못사용할까봐 getter와 setter를 쓰는것이다.
//setter가 있기 때문에 -1를 주면, 경고가 뜨고, 정상적인 나이가 입력된다면 이제 this.age를 value로 설정하게 되는것이다.
🤚🏻 변수이름 앞에 _ 을 붙여준 이유
setter
안에서 전달된 value를 this.age에 할당할 때 메모리의 값을 update 하는 것이 아니라 또 setter
를 호출하게 되는 것이다.그래서 이를 방지하기 위해 getter와 setter안에 쓰여지는 변수의 이름을 조금 다르게 만들어 주는 것이고 보통 앞에 _ 를 붙여준다.
✨ field는 기호( _ ) 가 들어간 age가 있지만 .age 라고 호출할 수 있고, 또 .age에 값을 할당할 수도 있는 이유는 내부적으로 getter와 setter를 이용하는 것이기 때문이다.
너무 최근에 추가되어져서 아직은 많은 개발자들이 쓰고 있지는 않다. 아직 사파리에서도 지원하지 않는다. 그래서 babel을 이용해야 한다.
class Experiment {
publicField = 2; //public (외부에서 접근가능)
#privateFiedl = 0; //private (class내부에서만 값이 보여지고|접근이되고|값의 변경이 가능하지만
// class외부에서는 이 값을 읽을 수도 변경할 수도 없다.
}
const experiment = new Experiment();
console.log(experiment.publicField); //2
console.log(experiment.privateField); //undefined
생성자를 쓰지 않고 저렇게 field를 정의할 수 있는데,
이것도 쓰기에는 아직 무리가 있다.
class 안에 있는 field와 method들은 새로운 Object를 만들 때마다 고대로 복제되어서 값만 우리가 지정한 값으로 변경이 되어서 만들어진다.
간혹 이런 오브젝트에 상관없이, 데이터에 상관없이! class가 가지고 있는 고유한 값과, 이런 데이터와 상관없이 동일하게 반복적으로 사용 되어지는 메소드가 있을 수 있다.
그런 것들을 이렇게 static 이라는 키워드를 이용해서 붙이면 오브젝트에 상관없이 클래스 자체에 연결된다.
class Article {
static publisher = 'Hello World';
constructor(articleNumber) {
this.articleNumber = articleNumber;
}
static printPublisher() {
console.log(Article.publisher);
}
}
const article1 = new Article(1);
const article2 = new Article(2);
console.log(article1.publisher); //undefined
console.log(article1.publisher);
이것이 undefined 로 나오는 이유는
→ static 은 object마다 할당되어지는 것이 아니라, class 자체(=여기서는 Article)에 붙어있기 때문이다. 그래서 이것을 호출하기 위해서는 다음과 같이 써야한다.
console.log(Article.publisher); //Hello World
Article.printPublisher(); //Hello World
a way for one class to extend another class.
class Shape {
constructor(width, height, color) { //width, height, color 총 3가지의 fields
this.width = width;
this.height = height;
this.color = color;
}
draw() { //draw하는 method
console.log(`drawing ${this.color} color of`);
}
getArea() { //getArea하는 method ..총 2개의 method
return this.width * this.height;
}
}
이렇게 Shape 이라는 class가 만들어져 있는데,
만약 Rectangle 이라는 class를 만들고 싶다면 동일하게 반복해서 하기 보다는
extends 라는 키워드를 이용해서 shape을 바로 연장해준다.
class Rectangle extends Shape {}
→ 이렇게만 정의해도 Shape에서 정의한 fields(3개)와 methods(2개)가 자동적으로 Rectangle에 포함된다.
const rectangle = new Rectangle (20,20, 'green');
rectangle.draw(); //drawing green color of
console.log(rectangle.getArea()); //400
✨ 그럼 Shape안에서 한번만 수정하면, extends로 만들어 준 것들 전부가 한번에 수정되어 바뀔 수 있다.
extends를 이용해 만들면서 overriding 을 사용하면, 필요한 함수만 다시 재정의해서 사용 할 수 있다.
🤚🏻 그런데 만약, 부모의 함수도 그대로 출력하고 싶다면? super 를 이용하면 된다.
class Triangle extends Shape {
//필요한 함수만 바로 재정의해서 사용할 수 있다. -> overriding
draw() {
super.draw(); //overriding을 하지만, 원래 Shape에 있던 draw()도 그대로 불러오고 싶으면 super 사용
console.log('🔺');
}
getArea() {
return (this.width * this.height) / 2;
//삼각형의 넓이는 2로 나누어 줘야 하니까 이 부분을 overriding 해주는거다.
}
}
const triangle = new Triangle(20,20,'yellow');
triangle.draw(); //draw yellow color of (super때문에 부모의 method도 출력)
//🔺 (이번에 새로 정의한 method)
console.log(triangle.getArea()); //200
Object는 class를 이용해서 만들어진 새로운 instance인데, instanceof
는 왼쪽에 있는 object가 오른쪽에 있는 class의 instance인지 아닌지(=이 object가 이 class를 이용해서 만들어진 것인지 아닌지)를 확인하는 것이다.
console.log(rectangle instanceof Rectangle); //true
console.log(triangle instanceof Rectangle); //false
console.log(triangle instanceof Triangle); //true
console.log(triangle instanceof Shape); //true (왜? Shape을 상속했으니까!)
console.log(triangle instanceof Object); //true
//🤔 왜? JavaScript에서 만든 모든 오브젝트 클래스들은 이 JavaScript에 있는 Object를 상속한거다!