빵 입니다.

Prototype를 사용한 함수형 프로그래밍, Todo 만들기 본문

프론트엔드/TODO 만들기

Prototype를 사용한 함수형 프로그래밍, Todo 만들기

bread-gee 2019. 3. 11. 16:41

기능 정의

  • Todo 입력
  • Todo 수정
  • Todo 삭제
  • Todo Total 갯수 체크
  • Todo 완료 갯수 체크
  • Todo 미완료 갯수 체크

자바스크립트는 프로토타입(Prototype) 기반의 언어라고 한다.

자바스크립트는 원형 객체를 복사하여 새로운 객체를 생성한다.

프로토타입은 객체를 확장하고 객체 지향적인 프로그래밍을 할 수 있게 해줍니다.


자바스크립트에서 프로토타입은 두 가지로 해석된다.

1. 객체 멤버인 __proto__ 속성이 참조하는 숨은 링크

어떠한 객체가 만들어지기 위해 그 객체의 모태가 되는 것으로 객체원형이 어떤 객체인지 가리키는 연결이다.

prototype에 대한 link는 상위에서 물려받은 객체의 프로토타입에 대한 정보이다.

빈객체의 원형은 자바스크립트의 최상위 객체인 Object이다.


2. 프로토타입 객체를 참조하는 Prototype 속성

prototype 속성은 객체가 생성될 당시 만들어지는 객체 자신의 원형이될 prototype 객체를 가리킨다. 

new 연산자를 통해 생성된 모든 객체의 원형이 되는 객체이다.


ex) 함수의 prototype은 함수 자체를 가르키며 이를 생성자(constructor)라 부른다.

new 연산자와 함께 호출된 함수는 다음과 같이 동작한다.

1. new 연산자로 Constructor 객체의 빈객체(인스턴스)를 생성하고, 이 인스턴스를 this로 바인딩한다.

(Constructor 객체의 this는 Constructor 객체를 가리키고, 인스턴스의 this는 인스턴스를 가리킨다.)

2. 생선된 인스턴스 객체의 this 객체의 __proto__속성을 Constructor 객체의 prototype 객체(prototype프로퍼티)를 연결한다.

3. 함수 종료시 해당 인스턴스에 연결된 this객체를 반환한다.



HTML

        

Todo

    CSS

    @charset "UTF-8";
    @import url(//fonts.googleapis.com/earlyaccess/jejugothic.css);
    
    .todo_wrap{width:300px; margin:0 auto;}
    .todo_wrap h1{text-align:center;}
    .input_wrap{background:red;}
    .input_wrap:after{content:""; display:block; clear:both;}
    .input_wrap input{box-sizing:border-box; float:left; width:231px; height:40px; outline:0 none; border:1px solid #999; text-indent:5px;}
    .input_wrap input:focus{border-color:#03cf5d;}
    .input_wrap button{box-sizing:border-box; float:left; width:70px; height:40px; margin-left:-1px; outline:0 none; border:1px solid #03cf5d; background:#03cf5d; color:#fff;}
    .input_wrap button:hover{cursor:pointer;}
    
    .todo_list{list-style-type:none; margin:0; padding:30px 0;}
    .todo_list li{line-height:30px; font-family:'Noto Sans KR', sans-serif; font-size:13px;}
    .todo_list li input{vertical-align:middle;}
    .todo_list li label{vertical-align:middle; cursor:pointer;}
    .todo_list li button{box-sizing:border-box; width:20px; height:20px; outline:0 none; border:0 none; background:#ffffff; line-height:20px; color:red; vertical-align:middle; cursor:pointer; transition:background-color 0.5s ease;}
    .todo_list li button:hover{background:#03cf5d;}
    .todo_list .complete{text-decoration:line-through;}
    
    .todo_count{}
    .todo_count>span{position:relative; display:inline-block; width:30%; font-size:12px; text-align:center;}
    .todo_count>span>strong{position:relative; top:1px; display:inline-block; color:#1aaf5c;}
    

    JAVASCRIPT

    const src   = `
        

    Todo

      {{#each todoArray}}
    • {{/each}}
    {{totalCnt}} 완료 {{comCnt}} 미완료 {{incomCnt}}
    `; function Todo(){ this.todoArray = []; this.template = Handlebars.compile(src); this.container = document.querySelector('#todoWrap'); this.container.addEventListener("click", this.onCreateItem.bind(this)); this.container.addEventListener("keypress", this.onCreateItem.bind(this)); this.container.addEventListener('change', this.onChangeStatus.bind(this)); this.container.addEventListener('click', this.onDeleteItem.bind(this)); this.updateView(); }; Todo.prototype.addArray = function(title){ this.todoArray.push({ title: title, id: Date.now(), chkState: false }); }; Todo.prototype.onCreateItem = function(e){ if(e.target.id === 'btnAdd' || e.which === 13){ let txtInput = document.querySelector('#txtInput'); if( txtInput.value ){ this.addArray(txtInput.value); this.updateView(); }else{ alert('할 일을 입력해주세요.'); } } }; Todo.prototype.onChangeStatus = function(e){ if (e.target.type === 'checkbox') { let id = +e.target.id; this.todoArray.find(todo => todo.id === id).chkState = e.target.checked; this.updateView(); } }; Todo.prototype.onDeleteItem = function(e){ if(e.target.name === 'btnDelete'){ let id = +e.target.dataset.id; this.todoArray = this.todoArray.filter(todo => todo.id != id); this.updateView(); } }; Todo.prototype.updateStatusBar = function(){ let totalCnt = this.todoArray.length; let comCnt = this.todoArray.filter(todo => todo.chkState).length; let incomCnt = this.todoArray.filter(todo => !todo.chkState).length; return { totalCnt, comCnt, incomCnt }; }; Todo.prototype.updateView = function(){ this.container.innerHTML = this.template(Object.assign({ todoArray: this.todoArray }, this.updateStatusBar() )); }; let app = new Todo();


    CODEPEN 확인

    https://codepen.io/bread_gee/pen/aMyVZW

    Comments