주석을 표시해두었습니다 a,b를 찾아보세요.
현재 각각의 생성자 함수에서 a,b 와 같은 방법으로 new 키워드를 사용했는지 아닌지를 판단하고 있습니다.
이러한 코드를 함수로 밖으로 빼면 더 간결하게 코드를 짤 수 있는데요.
<script>
// 이곳에서 코딩을 시작하세요!
function Validator() {
if (!(this instanceof Validator)) { // a
console.log(this instanceof Validator);
}
...
}
function TodoList(data, $app) {
if (!(this instanceof TodoList)) { // b
console.log(this instanceof TodoList);
throw new Error(ErrorMessage.EXCEPT_NEW);
}
...
}
const $target = document.querySelector('.App');
const validData = new Validator();
try {
const todoList = new TodoList(validData.validate(data), $target);
const todoList2 = new TodoList(validData.validate(data2), $target);
const todoList3 = new TodoList(validData.validate(data3), $target);
setTimeout(() => {
todoList.setState(data4, validData);
}, 2000);
} catch (e) {
console.log(e.message);
alert('뭔가 문제가 있습니다. 개발팀을 불러주세요.');
}
</script>
주석은 회색배경 글자로 편의상 쓰겠습니다.
isInstanceof 함수, a , b 에 주목해주세요.
isInstanceof 함수를 만들어줌으로써 중복되는 코드를 함수를 사용하여 리팩토링한 모습입니다.
<script>
// 이곳에서 코딩을 시작하세요!
const isInstanceof = (context, constructor) => { // isInstanceof 함수
if (!(context instanceof constructor)) {
throw new Error(ErrorMessage.EXCEPT_NEW);
}
};
function Validator() {
isInstanceof(this, Validator); // a
...
}
function TodoList(data, $app) {
isInstanceof(this, TodoList); // b
...
}
const $target = document.querySelector('.App');
try {
const validData = new Validator();
const todoList = new TodoList(validData.validate(data), $target);
const todoList2 = new TodoList(validData.validate(data2), $target);
const todoList3 = new TodoList(validData.validate(data3), $target);
setTimeout(() => {
todoList.setState(data4, validData);
}, 2000);
} catch (e) {
console.log(e.message);
alert('뭔가 문제가 있습니다. 개발팀을 불러주세요.');
}
</script>
너무 길어져서 접은글로 리팩토링 전 , 리팩토링 후 코드를 나타내겠습니다.
리팩토링 전
처음에 내가 짠 로직은 Validator 라는 함수를 만들었다.
그후 Validator 안의 this.validate 라는 메소드를 만들었다.
우선 이 로직으로 data를 validate 하기 위해서는 Validator라는 생성자함수를 호출을 해야했다.
이게 로직을 짤 때는 몰랐지만 필요없는 코드였다.
<script>
// 이곳에서 코딩을 시작하세요!
function Validator() {
if (!(this instanceof Validator)) {
console.log(this instanceof Validator);
throw new Error(ErrorMessage.EXCEPT_NEW);
}
this.isFalsy = (todoList) => {
if (!todoList) {
throw new Error(ErrorMessage.FALSY_VALUE);
}
};
this.isNotArray = (todoList) => {
if (!Array.isArray(todoList) || !todoList.length) {
throw new Error(ErrorMessage.ISNOT_ARRAY);
}
};
this.isNotObject = (todoList) => {
if (typeof todoList !== 'object') {
throw new Error(ErrorMessage.ISNOT_OBJECT);
}
};
this.isNotValidData = (todoList) => {
if (
todoList.some(
(item) =>
!item ||
!item.hasOwnProperty('text') ||
!item.hasOwnProperty('isCompleted')
)
) {
throw new Error(ErrorMessage.VALIDDATA);
}
};
this.validate = (todoList) => {
this.isFalsy(todoList);
this.isNotArray(todoList);
this.isNotObject(todoList);
this.isNotValidData(todoList);
return todoList;
};
}
function TodoList(data, $app) {
if (!(this instanceof TodoList)) {
console.log(this instanceof TodoList);
throw new Error(ErrorMessage.EXCEPT_NEW);
}
this.data = data;
this.$target = document.createElement('ul');
$app.appendChild(this.$target);
this.render = () => {
this.$target.innerHTML = `<ul>${this.data
.map(({ text, isCompleted }) =>
isCompleted ? `<li><s>${text}</s></li>` : `<li>${text}</li>`
)
.join('')}</ul>`;
};
this.setState = (nextData, validData) => {
validData.validate(nextData);
this.data = nextData;
this.render();
};
this.render();
}
const $target = document.querySelector('.App');
const validData = new Validator();
try {
const todoList = new TodoList(validData.validate(data), $target);
const todoList2 = new TodoList(validData.validate(data2), $target);
const todoList3 = new TodoList(validData.validate(data3), $target);
setTimeout(() => {
todoList.setState(data4, validData);
}, 2000);
} catch (e) {
console.log(e.message);
alert('뭔가 문제가 있습니다. 개발팀을 불러주세요.');
}
</script>
리팩토링 후
우선 Validator 함수에 있던 메소드를 모두 밖으로 빼준 모습이다.
isInstanceof, isFalsy, isNotArray, isNotArray, isNotObject 가 그 예시에 해당된다.
이제 이를 사용하기위해서 TodoList 생성자 함수 내부에 this.validate 메소드를 만들어주는 것이다.
그러면 나의 리팩토링 이전 코드처럼 Validator를 따로 호출할 필요도 없을 뿐더러
new TodoList( ) 를 호출할때 파라미터의 데이터를 검증하게 되므로 더욱 간단한 코드가 된다.
하나 헷갈렸던 부분이 있다. TodoList 생성자 함수 내부에 this.validate 메소드를 만들때 파라미터로 this.state를 넘겨주는 것을 볼 수 있다. 근데 이 로직을 이해할 당시 `어? this.state가 할당되기 전인데?` 라는 생각을 했다.
그러나 문제가 되지않은점은 this.validate()를 호출하는 시점이 this.state가 할당이 되고 난 다음이기 때문이다.
또한 타입스크립트를 사용하면 이러한 validate과정이 필요가 없어진다.
<script>
// 이곳에서 코딩을 시작하세요!
const isInstanceof = (context, constructor) => {
if (!(context instanceof constructor)) {
throw new Error(ErrorMessage.EXCEPT_NEW);
}
};
const isFalsy = (todoList) => {
if (!todoList) {
throw new Error(ErrorMessage.FALSY_VALUE);
}
};
const isNotArray = (todoList) => {
if (!Array.isArray(todoList) || !todoList.length) {
throw new Error(ErrorMessage.ISNOT_ARRAY);
}
};
const isNotObject = (todoList) => {
if (typeof todoList !== 'object') {
throw new Error(ErrorMessage.ISNOT_OBJECT);
}
};
const isNotValidData = (todoList) => {
if (
todoList.some(
(item) =>
!item ||
!item.hasOwnProperty('text') ||
!item.hasOwnProperty('isCompleted')
)
) {
throw new Error(ErrorMessage.VALIDDATA);
}
};
function TodoList(data, $app) {
this.validate = () => {
isInstanceof(this, TodoList);
isFalsy(this.data);
isNotArray(this.data);
isNotObject(this.data);
isNotValidData(this.data);
};
this.data = data;
this.validate();
this.$target = document.createElement('ul');
$app.appendChild(this.$target);
this.render = () => {
this.$target.innerHTML = `<ul>${this.data
.map(({ text, isCompleted }) =>
isCompleted ? `<li><s>${text}</s></li>` : `<li>${text}</li>`
)
.join('')}</ul>`;
};
this.setState = (nextData, validData) => {
this.data = nextData;
this.validate();
this.render();
};
this.render();
}
const $target = document.querySelector('.App');
try {
const todoList = new TodoList(data, $target);
const todoList2 = new TodoList(data2, $target);
const todoList3 = new TodoList(data3, $target);
setTimeout(() => {
todoList.setState(data4, validData);
}, 2000);
} catch (e) {
console.log(e.message);
alert('뭔가 문제가 있습니다. 개발팀을 불러주세요.');
}
</script>
'공부기록 > 바닐라 자바스크립트' 카테고리의 다른 글
동적인 DOM 객체 생성 (0) | 2022.07.19 |
---|---|
생성자의 파라미터를 객체로 받는것에 대하여 (0) | 2022.07.19 |
자바스크립트 배열 내 조건에 맞는 원소 구하기 (every, some 함수) (0) | 2022.07.11 |
Object.getOwnPropertyNames() vs Object.keys() (0) | 2022.07.11 |
typeof , instanceof 에 대한 공부 (0) | 2022.07.11 |