Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 16 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,22 @@
# todo
레벨2
ES6 Classes 적용.
요구사항
객체리터럴로 된 코드를 다시한번 ES6의 Class문법에 따라서 변경해본다.

### 설계
아래코드와 같이 동작되도록 한다.

### 플로우
const Health = class {
constructor(name,healthTime) {
this.name = name;
this.healthTime = healthTime;
}

1. 입력 -> 명령어
2. 명령어를 받아서 해석한다. -> add, show, update
3. add를 받았을 떄 todos에 받은 todo를 추가한다.
4. show를 받았을 때 같은 상태에 있는 것들을 출력한다.
5. update를 받았을 때 기존에 있는 상태를 update한다.
6. todo, doing, done
showHealth(){
debugger;
console.log(this.name + "님, 오늘은 " + this.healthTime + "에 운동을 하셨네요");
}


7. Model todos 라는 객체가 있고
todo안에는 id로 접근 가능한 todo가 있다
todo에는
id: {
todo: '할 일 내용'
state: 상태
time: {
startTime,
doneTime,
spendTime,
}
}

### 요구사항 소요시간결과의 복잡도 측정

todos에는 stateCounter가 있다.
상태들의 개수를 다 가지고 있다.
fastOne 가장 빨리 끝낸 친구에 id를 알고 있다.

1~30회 완료된 일이 늘어날수록 처음에는 그 횟수만큼 수행해서 최소값 최대값을 찾는다.
업데이트 된 일이 있으면 최대값, 최소값과 비교하여 id를 업데이트 한다.
시간복잡도는 O(n)일 것 같다.
지금 우선 생각으로는 최소값과 최대값을 저장해서 업데이트 될 때마다 비교하여 최소 최대값을 바꿔 주는 것이 좋은 방법이라고 생각하고 있다.
나쁜 방법은 매번 다 돌려서 최소/최대값을 찾는 것이다!



const ho = new Health("crong", "12:12");
ho.showHealth();
mdn의 ES6 Class를 활용해서 한다. 불필요한 상속구조는 하지 않는다.
36 changes: 36 additions & 0 deletions immutable/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Immutable collection조작
목표
데이터의 상태를 직접 변경하지 않고, 새로운 데이터로 만들어서 데이터를 업데이트 하는 방법을 안다.

데이터 변경 방법에 대한 고민
자바스크립트에서는 array와 object이라는 데이터를 다루는 collection이 존재하며, 어떤 이유로 삭제/변경/추가등 다양한 변경이 발생할 수 있다.

collection의 상태를 변경해야 한다면 어떻게 해야할까?

1) 직접 상태를 바꾼다.

2) 이전 상태를 보관해두고 새로운 collection을 만든다.

보통은 1)을 선택할 것 같다. 배열과 객체에 새로운 속성이나 데이터를 넣는건 당연해보인다.

하지만, 1)과 같이하면 몇가지 아쉬운점이 존재한다.

이전 상태를 되돌리기가 어렵다.
이전 상태와 현재상태를 유지하면서 동작해야 하는 경우가 존재할 수 있다.
새로운 데이터를 만듬으로써, 데이터의 변경 여부를, 쉽게 판단할 수 있다.(oldData !== newData)
그래서, 변경이 발생할 때마다, 새로운 collection을 만들면 더 좋다.

mutable
이미 만들어진 상태를 변경하는 것은 mutable이라고 한다. array와 object는 mutable이다.

아래 예제를 보면, myData정보가 계속 변경되고 있다.



### immutable 객체로 처리.
요구사항
add/update를 하면서 변경되는 todoList의 데이터를 immutable 하게 처리되도록 하자.

todoList의 상태가 변경될 때마다, 새로운 todoList데이터로 갱신되도록 한다.
immutable.js와 같은 라이브러리를 사용할 수 없다.
함수단위로 본인이 재사용할 수 있는 함수를 만들려고 노력한다.
45 changes: 45 additions & 0 deletions immutable/immutableStudy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
### Why Immutable

이전 상태를 되돌리기가 어렵다.
이전 상태와 현재상태를 유지하면서 동작해야 하는 경우가 존재할 수 있다.
새로운 데이터를 만듬으로써, 데이터의 변경 여부를, 쉽게 판단할 수 있다.(oldData !== newData)
그래서, 변경이 발생할 때마다, 새로운 collection을 만들면 더 좋다.

원본을 다른데서도 참조하고 있으면 상황이 꼬일 수 있는 점 +
데이터를 외부에서 받아온다고 생각해보자
내 페이스북 user정보를 받아왔다고 해서 거기서 조작을 한다고 하면 계속 같은 데이터를 참조하면 중간 과정을 기록하거나 볼 수 가 없다.
기능 단위로 생각 ->
브라우저 뒤로 가기 -> 캐쉬
한 번 실행 후



### immutable

immutable js -> why?
immutable은 생성되면 변할 수가 없다. array,list,fn 등은 reference타입으로 참조를 하고 있으므로


[미디엄글+_Immutable.js](https://medium.com/@AlexFaunt/immutablejs-worth-the-price-66391b8742d4)
함수형 프로그래밍의 핵심이라고 한다.functional programming

순수함수 Input -> OutPut

앱에서 Dom조작을 할 떄 -> 변화를 인지해야 되기 때문에 immutable을 쓴다?

input -> output이 분리되므로 data흐름을 추적하기 좋다.
퍼포먼스 -> memoization을 통해서 performance향상
ex) [1,2,3,4,5] 5->6으로 바꾸는 것 보다
[1,2,3,4 ,...6] 요렇게 합쳐주는 것이 더 ? why 바꾸려면 찾아줘야 되는 비용?

```
Simplified data flow through apps.
Removed requirement for defensive copying of data.
Optimisation through data change detection.
Performance enhancement through memoization
```


[why???_immutable](https://stackoverflow.com/questions/34385243/why-is-immutability-so-important-or-needed-in-javascript)

[_immutable_JS_hurt_?](https://softwareengineering.stackexchange.com/questions/304574/does-immutability-hurt-performance-in-javascript)
238 changes: 238 additions & 0 deletions immutable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
const notNumber = function(number) {
return isNaN(Number(number))
}

// Normal
// this.time = {horus, mins, seconds} 이런 객체 할당
// this.time = updateState(this.time, hours)
function objUpdateByKeyValue(state, property, item ) {
return Object.assign({}, state, {[property]: item});
}

function objUpdate(state, ...change){
return Object.assign({}, state, ...change)
}


// With Object Spread:
// function updateState(state, item) {
// return {
// ...state,
// [item.id]: item
// };
// }


const errMsg = {
notActions: `명령어는 add show done 중 하나입니다. ex) show$todo`,
wrongTodoState: 'state는 todo, doing, done 중 하나입니다',
notNumber: 'id 값은 숫자여야 합니다. ex) update$1$done',
notHaveThisId: '해당 id 값이 없습니다',
emptyTask: `todo에 내용이 없습니다`
}

//Print는 데이터를 읽기만 하므로 Pass

const PrintTodo = {
added(todos){
const addedOne = todos.todos[todos.currentId]
const { id, task } = addedOne
console.log(`id: ${id} ${task} 항목이 새로 추가 되었습니다.`)
this.stateCounter(todos.stateCounter)
},
stateCounter(stateCounter){
const {todo, doing, done} = stateCounter
console.log(`현재상태ㅣ todo: ${todo} 개 doing: ${doing} 개 done: ${done}개`)
},
updated(todos, ID){
const updatedOne = todos.todos[ID]
const {task, state, id} = updatedOne
console.log(`업데이트 된 todo는 id: ${id} todo: ${task}: ${state}\n`);
this.stateCounter(todos.stateCounter);
if(state === 'done') {
this.spentTime(updatedOne, todos);
}
},
spentTime(updatedOne, todos){
const { hours, mins, seconds} = updatedOne.time.spentTimeHMS
console.log(`${updatedOne.id} ${updatedOne.task}의 걸린시간은 ${hours} 시간 ${mins} 분 ${seconds} 초\n`)
console.log('가장 빨리 끝낸 일', todos.fastest, '가장 늦게 끝낸 일 ', todos.slowest);
},
}

// Todo에서 Immutable로 Data를 변경할 수 있는 부분을 찾아보자 !!!
// time만 reference type -> Immutable하게 변경

class Todo {
constructor(id, task){
this.id = id,
this.task = task
this.state = 'todo'
this.time = {}
this.Seconds = 1000;
}
update(state){
this.state = state;
}
getState(){
return this.state;
}
addTimeInfo(state){
this.time = objUpdateByKeyValue(this.time, state, new Date())
if(state==='done'){
this.recordSpendTime()
this.convertToSpendTimeHMS(this.time.spentTime)
}
}
recordSpendTime(){
const timeGap = this.time.done - this.time.doing
this.time = objUpdateByKeyValue(this.time, 'spentTime', parseInt(timeGap/this.Seconds))
// this.time.spentTime = parseInt(timeGap/this.Seconds)
}
convertToSpendTimeHMS() {
const spentTime = this.time.spentTime
const hours = parseInt((spentTime / 3600))
let restTime = spentTime - hours * 3600
const mins = parseInt((restTime / 60))
restTime = restTime - mins * 60
const seconds = restTime;
this.time.spentTimeHMS = objUpdate(this.time.spentTimeHMS, {hours},{mins},{seconds})
// this.time.spentTimeHMS = {hours, mins, seconds}
}
}


// Todos immutable로 변경

const Todos = class {
constructor(name, todos={}){
this.name = name;
this.todos = todos
this.currentId = 0,
this.stateCounter = {
todo: 0,
doing: 0,
done: 0,
}
this.fastest,
this.slowest,
this.actionsKey = ['add', 'show', 'update']
this.statesKey = ['todo', 'doing', 'done']
}
addCurrentId(currentId){
return currentId +=1
}
plusStateCounter(state){
return objUpdate(this.stateCounter, {[state]: this.stateCounter[state]+1})
}
minusStateCounter(state){
return objUpdate(this.stateCounter, {[state]: this.stateCounter[state]-1})
}
add(todo){
if(!todo.trim()) console.log(errMsg.emptyTask)
this.currentId = this.addCurrentId(this.currentId);
const currentId = this.currentId;
const newTodo = new Todo(currentId, todo)
// immutable add
this.todos = objUpdate(this.todos, {[currentId]: newTodo})
this.stateCounter = this.plusStateCounter('todo')
newTodo.addTimeInfo(newTodo.state)
}
show(state){
const todos = this.todos
const sameStates = Object.values(todos).filter(todo => todo.state===state)
this.printSameTasks(sameStates, state)
}
printSameTasks(todos, state) {
const resultTasks = todos.reduce((ac, todo) => {
return ac += `${todo.id}, ${todo.task}\n`
}, `원하는 상태목록은 :D ${state}\n`)
console.log(resultTasks)
}
update(id, state){
if (notNumber(id)) console.log(errMsg.notNumber)
if (!this.todos[id]) console.log(errMsg.notHaveThisId)
const willUpdatedOne = this.todos[id]
const lastState = willUpdatedOne.getState()
willUpdatedOne.update(state)
this.updateStateCounter(lastState, state);
this.updateTime(id, state)
}
updateStateCounter(lastState, nowState){
this.stateCounter = this.minusStateCounter(lastState)
this.stateCounter = this.plusStateCounter(nowState)
}
updateTime(id, todoState) {
const willUpdateTimeTodo = this.todos[id]
willUpdateTimeTodo.addTimeInfo(todoState);
if (todoState === 'done'){
willUpdateTimeTodo.recordSpendTime();
willUpdateTimeTodo.convertToSpendTimeHMS(willUpdateTimeTodo.spentTime)
this.saveFastest(id)
this.saveSlowest(id)
}
}
saveFastest(id){
this.fastest = this.fastest ?
this.todos[this.fastest].time.spentTime > this.todos[id].time.spentTime ? id : this.fastest
: id
}
saveSlowest(id){
this.slowest = this.slowest ?
this.todos[this.slowest].time.spentTime < this.todos[id].time.spentTime ? id : this.slowest
: id
}
}

const $Todos = new Todos('$todo', {})

// command('show$todo')
// command('update$1$doing');

// command('add$React공부')
// command('show$todo');
// command('update$1$doing');


$Todos.add('자바스크립트공부')
PrintTodo.added($Todos);
$Todos.add('ES6공부')
PrintTodo.added($Todos);
$Todos.add('React공부')
PrintTodo.added($Todos);
$Todos.show('todo')
$Todos.update(1,'doing')
PrintTodo.updated($Todos,1)
// $Todos.update(1,'doing')
// $Todos.update(3,'doing')
// $Todos.update(3,'done')


function timeDelay(arr, time, i = 0) {
if (arr.length === i) return;
setTimeout(() => {
arr[i]();
i += 1;
return timeDelay(arr, time, i);
}, time)
}

timeDelay([
() => $Todos.update(1,'done'),
()=> PrintTodo.updated($Todos,3),
()=> $Todos.update(3,'doing'),
()=> $Todos.update(3,'done'),
()=> PrintTodo.updated($Todos,3),
// ()=> console.log(JSON.stringify($Todos, null, 2))
]
, 1000);

timeDelay([
()=> $Todos.update(2,'doing'),
()=> $Todos.update(2,'done'),
()=> PrintTodo.updated($Todos,2),
()=> console.log(JSON.stringify($Todos, null, 2))
]
, 2000);

// console.log(JSON.stringify($Todos, null, 2));
Loading