개인노트 nomad ES6의 정석 #10 Classes

2023. 2. 19. 20:07개인노트-인강

# 10.0 Introduction to Classes

Class는 일종의 blueprint의 역할을 합니다.

class User {
    constructor() {
        this.username = "Nicolas";
    }
    sayHello() {
        console.log("Hello");
    }
}

클래스는 안에 constructor를 가지고 있습니다. 

constructor는 Class를 말 그대로 construct (구성) 한다는의미의 constructor입니다.

 

이 Class를 사용하려면 Class를 생성해주어야합니다. 생성한다. 구성(construct)한다.

const sexyUser = new User();

위해서 sexyUser는 Class의 instance 입니다. instance 는 blueprint 를 토대로한 살아있는(메모리에 적재된) 상태입니다.

console.log(sexyUser.username);
// 결과
// Nicolas

sexyUser.sayHello();
// 결과
// Hello

 

새로운 인스턴스들을 계속 생성할 수 있습니다.

class User {
    constructor() {
        this.username = "Nicolas";
    }
    sayHello() {
        console.log("Hello, I'm Nicolas");
    }
}

const sexyUser = new User();
const uglyUser = new User();

sexyUser.sayHello();
uglyUser.sayHello();
// 결과
// Hello, I'm Nicolas
// Hello, I'm Nicolas

 

아래처럼 object를 이용할 수도 있지만, class하고 다른 점은, class는 constructor에 argument를 전달하여 매번 다른 값을 할당할 수 있습니다.

// object인 경우
const baseObject = {
    username: "nicolas",
    sayHi: function () {
        console.log("hi nicolas");
    },
};

const sexyUser = baseObject;
const uglyUser = baseObject;

sexyUser.sayHello();
uglyUser.sayHello();
// class인 경우
class SayName {
    constructor(name) {
        this.name = name;
    }
    SayNamefunc() {
        console.log(`My name is ${this.name}`);
    }
}

const callFunc = new SayName("Joey");
callFunc.SayNamefunc();
// 결과
// My name is Joey

 

Class는 기본적으로 일종의 object의 공장입니다.

 

# 10.1 Extending Classes

class User {
    constructor(name, lastname, email, password) {
        this.username = name;
        this.lastname = lastname;
        this.email = email;
        this.password = password;
    }
    sayHello() {
        console.log(`Hello, my name is ${this.username}`);
    }
    getProfile() {
        console.log(`${this.username} ${this.email} ${this.password}`);
    }
    updatePassword(newPassword, currentPassword) {
        if (currentPassword === this.password) {
            this.password = newPassword;
        } else {
            console.log("can't change password");
        }
    }
}

class Admin extends User {
    // constructor(superadmin) {
        // this.superadmin = superadmin;
    // }
    deleteWebsite() {
        console.log("Boom!");
    }
}

'this'는 클래스 자체를 가리킵니다.

 

# 10.2 super

super() 는 base class 를 호출합니다.

class User {
constructor({ username, lastname, email, password }) {
this.username = username;
this.lastname = lastname;
this.email = email;
this.password = password;
}

getProfile() {
console.log(`${this.username} ${this.email} ${this.password}`);
}
updatepassword(newpassword, currentpassword) {
if (currentpassword === this.password) {
this.password = newpassword;
} else {
console.log("can't change password");
}
}
}
const sexyUser = new User({
username: "Nico",
lastname: "serrano",
email: "nico@com",
password: "1234",
});

class Admin extends User {
constructor({ username, lastname, email, password, superadmin, isActive }) {
super({ username, lastname, email, password });
this.superadmin = superadmin;
this.isActive = isActive;
}
deleteWebsite() {
console.log("Boom!");
}
}

const admin = new Admin({
username: "Nico",
lastname: "serrano",
email: "nico@com",
password: "1234",
superadmin: true,
isActive: true,
});

 

## counter 구현으로 class 활용

class Counter {
    constructor({ initialNumber = 0, counterId, plusId, minusId }) {
        this.count = initialNumber;
        this.counter = document.getElementById(counterId);
        this.counter.innerText = initialNumber;
        this.plusBtn = document.getElementById(plusId);
        this.minusBtn = document.getElementById(minusId);
        this.addEventListeners();
    }
    addEventListeners() {
        this.plusBtn.addEventListener("click", this.increase);
        this.minusBtn.addEventListener("click", this.decrease);
    }
    increase() {
        this.count = this.count + 1;
        this.repaintCount(); // error
    }
    decrease() {
        this.count = this.count - 1;
        this.repaintCount(); // error
    }
    repaintCount() {
        this.counter.innerText = this.count;
    }
}

new Counter({ counterId: "count", plusId: "add", minusId: "minus" });

에러 내용

# 10.3 WTF is this

위에서 this.repaintCount()의 this는 Counter Class를 가리키지 않고, HTMLButtonElement에서 repaintCount를 찾으려고 시도하고 없어서 error가 발생했습니다.

 

반대로 this.plusBtn.addEventListener("click", this.increase); 에서 this는 제대로 Counter Class를 가리킵니다.

    // ...
    addEventListeners() {
        this.plusBtn.addEventListener("click", this.increase); // Counter Class를 가리킴.
        this.minusBtn.addEventListener("click", this.decrease);
    }
    increase() {
        this.count = this.count + 1; // increase 메소드 안에서의 this는 Button Element를 가리킴.
        this.repaintCount(); // error
    }
    // ...

 

addEventListener 처럼 this에 영향을 주는 경우, 아래처럼 arrow function을 사용하면 this의 문제가 해결됩니다.

    // ...
    addEventListeners() {
        this.plusBtn.addEventListener("click", this.increase); // Counter Class를 가리킴.
        this.minusBtn.addEventListener("click", this.decrease);
    }
    // 화살표 함수로 수정..
    increase = () => {
        this.count = this.count + 1; // Counter Class를 가리킴.
        this.repaintCount(); // Counter Class를 가리킴.
    }
    // ...

 

## 정리

 

eventListener 안에 event의 handler를 넣으면 event target을 가리키는 this를 가지게 됩니다.

즉, eventLister를 target에 add 할 때, 이 event의 handler는 this를 event target을 가르키게 합니다.

 

## 활용

위처럼 class를 이용하게 되면 똑같은 기능이 필요한 부분에 같은 기능을 복제할 수 있습니다.

// ...
new Counter({ counterId: "count", plusId: "add", minusId: "minus" });
new Counter({ counterId: "count2", plusId: "add2", minusId: "minus2", initialNumber: 66 });