아무 생각 없이 당연하다는듯이 Class로 진행을 했지만, 정작 왜 Class를 선택 했고, Function에 비해 어떤 부분이 더 이점을 가지는지 몰랐다.
반성(?)을 하는 차원에서 글을 다루고 SPA 프로젝트 진행에 대한 글쓰기를 이어나가보려고 한다.
1. 기본 사용 방법
- 기본 사용 방법은 다음과 같다
class TodoModel {
constructor(data) {
this.todos = [];
this.data = data;
}
addData() {
console.log(`${data} add Data`);
}
add() {
console.log('add');
}
}
export default TodoModel;
const todoModel = new TodoModel('input');
todoModel.addData();
- Factory Function
function TodoModel(data) {
const todos = [];
function addData() {
console.log(`${data} addData`);
}
function add() { console.log('add'); }
return Object.freeze({
addData,
});
}
export default TodoModel;
const todoModel = TodoModel('input');
todoModel.addData();
2. 캡슐화
- 내부 변수 또는 감추고 싶은 함수에 접근이 가능 여부
- 캡슐화가 안되면 _보안 이슈 가능성 농후!_
- 기본적으로 function은 캡슐화가 되지만, class는 캡슐화가 되지 않았었다. 그러나! nodejs 12.0.0 버전부터는 Private class fields를 사용하면 class도 캡슐화 가능!
class TodoModel {
#todos;
constructor(data) {
this.#todos = [];
this.data = data;
}
// 이하 생략
}
3. 불변성
- 정의된 함수를 변경할 수 있는가! 를 말한다.
- 보안을 위해 함수가 변경되지 않는 것이 좋다. (특수한 상황에 따라서 변경이 필요할 수는 있으나, 권장되는 방식은 아님!)
- class에서는 재할당을 통해 함수 변경이 가능하나, function에서는 불가능함. 그러나 static을 사용하면 class에서 개선이 가능하지만, 인스턴스화 되지 않으므로 사용법에 주의가 필요하다.
class TodoModel {
#todos;
constructor(data) {
this.#todos = [];
this.data = data;
}
addData() {
console.log('addData');
}
static add() {
console.log('add');
}
}
TodoModel.add(); // add
TodoModel.add = function() {
console.log("a new add")
} // Invalid left-hand side in assignment
4. 상속과 구성
- class에서는 상위 class로부터 상속을 받으면 상속 받은 모든 method를 사용해야 하지만, factory는 구성을 하기 때문에 선별적으로 사용할 수 있다.
class Person {
eat() {
console.log('I am eating');
}
breathe() {
console.log('I am breathing');
}
swim() {
console.log('I am swimming');
}
}
class Wizard extends Person {
trick() {
console.log('I am doing a trick');
}
}
const harry = new Wizard();
const ron = new Wizard();
// Harry can:
harry.eat(); // I am eating
harry.breathe(); // I am breathing
harry.swim(); // I am swimming
harry.trick(); // I am doing a trick
// Ron can:
ron.eat(); // I am eating
ron.breathe(); // I am breathing
ron.swim(); // I am swimming
ron.trick(); // I am doing a trick
const Person = () => {
return {
eat: () => {
console.log('I am eating');
},
breathe: () => {
console.log('I am breathing');
},
swim: () => {
console.log('I am swimming');
},
};
};
const Trick = () => {
return {
trick: () => {
console.log('I am doing a trick');
},
};
};
const Wizard = () => {
return {
eat: Person().eat,
breathe: Person().breathe,
trick: Trick().trick,
};
};
const Muggle = () => {
return {
eat: Person().eat,
breathe: Person().breathe,
swim: Person().swim,
};
};
// Harry can:
const harry = Wizard();
harry.eat(); // I am eating
harry.breathe(); // I am breathing
harry.trick(); // I am doing a trick
// Ron can:
const ron = Muggle();
ron.eat(); // I am eating
ron.breathe(); // I am breathing
ron.swim(); // I am swimming
5. this
- class에서는 this 문법을 사용할 수 있으나 factory function에서는 this 문법을 사용할 수 없다!!!
- this 문법을 사용할 때에는 컨텍스트 손실 문제가 발생할 수 있기 때문에 사용에 유의가 필요하다.
class TodoModel() {
constructor() {
this.todos = [];
}
reload() {
setTimeout(function log() {
console.log(this.todos)
}, 0);
}
}
todoModel.reload(); // undefined
6. 메모리
- class의 모든 메서드는 프로토 타입 객체에서 한 번 생성되고 모든 인스턴스에서 공유된다. 그러나! 여러 동일한 객체를 만들 때 function의 경우 많은 메모리 비용이 필요하다.
7. 결론
- 메모리 사용을 고려한 프로젝트인가 아니면 보안성이 우선시되는 프로젝트인가에 따라 다를 듯 하다.(class도 보안 요소 추가 가능)
이 글이 누군가에게는 도움이 되길 바라며...