유데미 강의 JavaScript 완벽 가이드 : 초급 + 고급 마스터 과정을 들으면서 자바스크립트를 다시 한 번 익히는 중이다. 계속되는 포스팅에서 강의를 듣고 미처 몰랐던 부분, 심화 이해가 필요한 부분에 대해 주제별로 간단하게 기록하겠다.
이번 챕터에선 class, 생성자함수, 프로토타입, 객체지향 프로그래밍에 대해서 배웠다. 사실 여러번 공부했던 챕터인데도 명확하게 이해를 못하고 넘어갔던지라 이번에도 쉽지는 않았다. 게다가 코드를 따라하다보면 리액트가 있는데 '이걸 왜 굳이..'라는 생각이 자꾸 들어서 학습 의욕이 많이 떨어졌다. 그래도 중요하다고 다들 말하니까..이해 안되는 부분은 계속 반복해서 익혔다.
객체를 생성하기 위해 변수와 메소드를 정의하는 일종의 틀이다. 이 틀을 사용해 인스턴스라 불리는 객체를 생성할 수 있다. 클래스는 프로퍼티와 메소드를 포함하며, 이는 객체의 상태와 동작을 정의한다.
프로토타입은 JavaScript와 같은 프로토타입 기반 언어에서 객체 간에 특성을 공유하기 위한 메커니즘이다. 각 객체는 다른 객체를 자신의 프로토타입으로 참조할 수 있고, 프로토타입의 속성이나 메소드를 상속받을 수 있다. 이는 코드의 재사용성을 높이고 메모리 사용을 최소화하는데 도움이 된다.
객체 지향 프로그래밍은 프로그램을 객체의 집합으로 보고, 각 객체가 데이터와 해당 데이터를 다루는 메소드를 함께 포함하게 하는 프로그래밍 방식이다. 이를 통해 코드의 재사용성, 모듈성, 유지 보수성을 향상시킬 수 있다.
class DOMHelper {
static clearEventListner(el) {
const cloneEl = el.cloneNode(true);
el.replaceWith(cloneEl);
return cloneEl;
}
static moveEl(elId, targetId) {
const el = document.getElementById(elId);
const targetEl = document.querySelector(targetId);
targetEl.append(el);
}
}
class Component {
constructor(hostElId, insertBefore = false) {
if (hostElId) {
this.hostEl = document.getElementById(hostElId);
} else {
this.hostEl = document.body;
}
this.insertBefore = insertBefore;
}
detach() {
if (this.el) this.el.remove();
}
attach() {
this.hostEl.insertAdjacentElement(
this.insertBefore ? 'afterbegin' : 'beforeend',
this.el
);
}
}
class Tooltip extends Component {
constructor(closeNotifier) {
super();
this.closeNotifier = closeNotifier;
this.create();
}
closeTooltip = () => {
this.detach();
this.closeNotifier();
};
create() {
const el = document.createElement('div');
el.className = 'card';
el.textContent = 'tooltip';
el.addEventListener('click', this.closeTooltip);
this.el = el;
}
}
class Project {
isOpenTooltip = false;
constructor(id, switchProject, type) {
this.id = id;
this.switchProject = switchProject;
this.connectMoreInfoBtn();
this.connectSwitchBtn(type);
}
openTooltip() {
if (this.isOpenTooltip) return;
const tooltip = new Tooltip(() => (this.isOpenTooltip = false));
tooltip.attach();
this.isOpenTooltip = true;
}
connectMoreInfoBtn() {
const projectEl = document.getElementById(this.id);
const btnEl = projectEl.querySelector('button:first-of-type');
btnEl.addEventListener('click', this.openTooltip);
}
connectSwitchBtn(type) {
const projectEl = document.getElementById(this.id);
let btn = projectEl.querySelector('button:last-of-type');
btn = DOMHelper.clearEventListner(btn);
btn.textContent = type === 'active' ? 'Finish' : 'Activate';
btn.addEventListener('click', () => this.switchProject(this.id));
}
updateProject(switchProject, type) {
this.switchProject = switchProject;
this.connectSwitchBtn(type);
}
}
class ProjectList {
projects = [];
constructor(type) {
this.type = type;
const projectEls = document.querySelectorAll(`#${type}-projects li`);
for (const el of projectEls) {
this.projects.push(
new Project(el.id, this.switchProject.bind(this), this.type)
);
}
}
addProject(project) {
this.projects.push(project);
DOMHelper.moveEl(project.id, `#${this.type}-projects ul`);
project.updateProject(this.switchProject.bind(this), this.type);
}
setSwitchHandler (switchHandler){
this.switchHandler = switchHandler;
}
switchProject(id){
this.switchHandler(this.projects.find(p => p.id === id));
this.projects = this.projects.filter(p => p.id !== id)
}
}
class App {
static init(){
const activeList = new ProjectList('active')
const finishedList = new ProjectList('finished')
activeList.setSwitchHandler(finishedList.addProject.bind(finishedList));
finishedList.setSwitchHandler(activeList.addProject.bind(activeList));
}
}
App.init();