# Class

## Class : 관련있는 변수나 함수들을 묶어 놓은 것

* Class의 안에는 **field**(속성), **method**(행동)가 들어있음
* 내부적인 변수 & 외부적인 변수를 나눔 → incapsulation **캡슐화**
* 클래스를 이용해서 상속과 다양성이 일어날 수 있음\
  이러한 모든 것들이 가능한 것이 **객체지향 언어**

## Class vs Object

### 🐡붕어빵을 예시로 들어보자!

{% tabs %}
{% tab title="Class" %}
**Class :** 정의만 해 놓은 것

* **template**(or 청사진) : 객체를 만들 수 있는 **틀**
* **declare once** : class 안에 어떠한 데이터가 들어 올 수 있는지 정의 해 놓고 **한 번만 선언**
* **no data in** :  class 자체에는 **데이터가 들어있지 않음** (틀 템플릿만 정의 됨)
{% endtab %}

{% tab title="Object" %}
**Object** : class를 이용해서 실제로 데이터를 넣어 만든 것

* **instance of a class** : class를 이용해서 새로운 **instance(실체화)**&#xB97C; 생성하면 object가 됨
* **reated many times** : class를 이용해서 굉장히 많이 만들 수 있음
* **data in** : class는 정의만 한 것이라 실제로 메모리에 올라가지 않지만,\
  실제로 데이터를 넣으면 object는 메모리에도 올라가게 됨
{% endtab %}
{% endtabs %}

> Class = 붕어빵 틀, Object = 팥붕어빵

{% hint style="info" %}
붕어빵이라는 template를 사용 \
→ 팥과 크림이라는 Data가 있음\
→ 팥을 넣으면 팥붕어빵 / 크림을 넣으면 크림붕어빵이 됨&#x20;

\
▶ 붕어빵을 만들기 위해 정의한 **붕어빵의 틀은 Class**\
▶ 이렇게 Class에 팥과 크림을 넣어 만들어진 **붕어빵 자체는 Object**
{% endhint %}

### 1. Class declarations

```javascript
'use strict';

class Person {
  // constructor
  constructor(name, age) {
    // fields
    this.name = name;
    this.age = age;
  }
  // methods
  speak() {
    console.log(`${this.name}: hello!`);
  }
}

const ellie = new Person('ellie', 20);
console.log(ellie.name);
console.log(ellie.age);
ellie.speak();
```

### 2. Getter and Setters

```javascript
class User {
  constructor(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
  }
  
  get age() { //이해가 어렵 다시 찬찬히 읽어보기
    return this._age;
  }
  set age(value) {
    // if (value < 0) {
    //     throw Error('age can not be negative');
    // }
    this._age = value < 0 ? 0 : value;
  } //값을 설정하는 것이기 때문에 value를 가져와야함.
}

const user1 = new User("steve", "Job", -1);
console.log(user1.age);
```

### 3. Fields (public, private)

```javascript
// Too soon!
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Class_fields
class Experiment {
  publicField = 2;   //외부에서 접근 가능
  #privateField = 0; //클래스 내부에서만 값이 보여지고 접근 가능
}
const experiment = new Experiment();
console.log(experiment.publicField);
console.log(experiment.privateField);
```

### 4. Static properties and methods

```javascript
// Too soon!
class Article {
  static publisher = "Dream Coding";
  constructor(articleNumber) {
    this.articleNumber = articleNumber;
  }
  static printPublisher() {
    console.log(Article.publisher);
  }
}

const article1 = new Article(1);
const article2 = new Article(1);
console.log(Article.publisher);
Article.printPublisher();
```

### 5. Inheritance

```javascript
// a way for one class to extend another class
class Shape {
    constructor(width, height, color) {
        this.width = width;
        this.height = height;
        this.color = color;
    }

    draw() {
        console.log(`drawing ${this.color} color!`); //drawing blue color!
    }
    
    getArea() {
        return this.width * this.height;
    }
}

//extends라는 keyword를 이용해서 shape을 연장
class Rectangle extends Shape {}
class Triangle extends Shape {
  draw() {
    super.draw();
    console.log('🔺'); //drawing red color!
  }
  getArea() {
    return (this.width * this.height) / 2;
  }
  
  toString() {
    return `Triangle: color: ${this.color}`;
  }
}

const rectangle = new Rectangle(20, 20, 'blue');
rectangle.draw();
console.log(rectangle.getArea());
const triangle = new Triangle(20, 20, 'red');
triangle.draw();
console.log(triangle.getArea());
```

### 6. Class checking : instanceOf

```javascript
// 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
console.log(triangle instanceof Object);     // true
console.log(triangle.toString());
```
