티스토리 뷰
2) 생성자패턴으로 TabUI만들기
이전의 Tab UI를 prototype을 활용하여 객체를 만드는 클래스 형태의 코드로 만들어보겠습니다.
자바스크립트 객체 다시 이해하기
- 전역공간에 구현된 코드를 prototype기반의 클래스로 구현해볼 겁니다. 이전에 구현했던 코드는 아래와 같습니다.
링크 바로가기
<html> <header> <link rel="stylesheet" href="tabui.css"> <style> h2 { text-align: center } h2, h4 { margin: 0px; } .tab { width: 600px; margin: 0px auto; } .tabmenu { background-color: bisque; } .tabmenu>div { display: inline-block; width: 146px; height: 50px; line-height: 50px; text-align: center; cursor: pointer; } .content { padding: 5%; background-color: antiquewhite; } </style> </header>
<body> <h2> TAB UI TEST</h2>
<div class="tab"> <div class="tabmenu"> <div>crong</div> <div>jk</div> <div>pobi</div> <div>honux</div> </div> <section class="content"> <h4>hello jk</h4> <p>golf, facebook</p> </section> </div> <script> function makeTemplate(data, clickedName) { var html = document.getElementById("tabcontent").innerHTML; var resultHTML = ""; for (var i = 0; i < data.length; i++) { if (data[i].name === clickedName) { resultHTML = html.replace("{name}", data[i].name) .replace("{favorites}", data[i].favorites.join(" ")); break; } } document.querySelector(".content").innerHTML = resultHTML; } function sendAjax(url, clickedName) { var oReq = new XMLHttpRequest(); oReq.addEventListener("load", function () { var data = JSON.parse(oReq.responseText); makeTemplate(data, clickedName); }); oReq.open("GET", url); oReq.send(); } var tabmenu = document.querySelector(".tabmenu"); tabmenu.addEventListener("click", function (evt) { sendAjax("./json.txt", evt.target.innerText); }); </script>
<script id="tabcontent" type="my-template"> <h4>hello {name}</h4> <p>{favorites}</p> </script> </body> </html> |
prototype 기반 클래스 코드
- prototype기반 코드는 하나의 클래스(모듈)로 만드는 것으로, 기존코드의 큰 수정 없이 변경할 수 있습니다.
- 우리는 지금처럼 비슷한 기능 덩어리를 하나의 객체, 즉 클래스 형태로 만들 수가 있습니다.
- 영상에 노출된 코드는 아래에서도 확인할 수 있습니다.
링크 바로가기
<script> function Tab(tabElement) { // this.tabmenu = document.querySelector(".tabmenu"); this.tabmenu = tabElement; this.registerEvents(); } Tab.prototype = { // prototype 객체를 오버라이딩. 참고로 constructor라는 속성이 prototype에 있는데 그것도 없어져 버려요. 그래서 그거를 따로 선언해주긴 해야 돼요. 그 부분은 생략합니다. registerEvents : function() { this.tabmenu.addEventListener("click", function (evt) { this.sendAjax("./json.txt", evt.target.innerText); // 여기서 this는 달라지므로 bind(this)를 해야 합니다. bind를 안하면 가리키는 것이 tabmenu가 되기 때문입니다. }.bind(this)); }, sendAjax : function(url, clickedName) { var oReq = new XMLHttpRequest(); oReq.addEventListener("load", function () { var data = JSON.parse(oReq.responseText); this.makeTemplate(data, clickedName); }.bind(this)); oReq.open("GET", url); oReq.send(); }, makeTemplate : function(data, clickedName) { var html = document.getElementById("tabcontent").innerHTML; var resultHTML = ""; for (var i = 0; i < data.length; i++) { if (data[i].name === clickedName) { resultHTML = html.replace("{name}", data[i].name) .replace("{favorites}", data[i].favorites.join(" ")); break; } } document.querySelector(".content").innerHTML = resultHTML } } var tabmenu = document.querySelector(".tabmenu"); var o = new Tab(tabmenu); </script> |
- object literal은 arrow 함수를 쓰면 조금 문제가 생길 수 있습니다. 그래서 object literal 안에서는 arrow 함수를 쓰지 않는 것을 권장합니다.
- Tab이 실행됐을 때 this.registerEvents()가 실행이 될 거고 registerEvents()가 this로 prototype에 있는 객체를 가리킬 수가 있어서 메서드들이 실행될 겁니다.
- tabmenu에 addEventListener 하고 sendAjax메서드를 수행하는데 this로 접근해야 됩니다. 근데 sendAjax의 this가 이때는 달라질 겁니다. 그래서 bind(this)를 해야 됩니다. 왜냐면 bind를 안 해주면 this가 가리키는 게 tabmenu가 아닌 다른 것을 가리킬 겁니다.
- this를 사용하여 makeTemplate을 가져오므로 ajax 콜백 함수에도 bind를 써줍니다. 쓰지 않는다면 여기는 아마 XMLHttpRequest 객체를 가리킬 거예요.
- 객체 안에서, function Tab() 안에서 this.tabmenu = document.querySelector(".tabmenu"); 처럼 속성값들을 늘려서 this로 쭉 나열하여 사용할 수도 있습니다. 그러나 객체 내의 전역변수로 사용하는 느낌이라 선호하지 않는 경우도 있습니다.
- 또는 아예 클래스 밖에서 인자로 받아서 사용할 수도 있습니다. 그러니까 this.tabmenu를 좀 더 클래스말고도 범용적으로 쓰려면 tabmenu를 클래스 밖에서 선언하여 인자로 넣어줄 수도 있습니다. 객체 안에서 this.tabmenu = document.querySelector(".tabmenu"); 라 코딩하면 Tab 객체는 HTML의 tabmenu에 dependency가 있는건데 인자로 받으면 dependency가 사라집니다. function Tab(tabElement) { this.tabmenu = tabElement 이렇게 써주면 tabmenu에 tabElement가 디폴트로 들어가는 거예요. 그러면 의존성이 없어진 코드가 되는 겁니다.
- 이런 식으로 하나의 Tab 클래스를 메서드를 여러 개 넣으면서 만들 수가 있습니다.
생각해보기
- 자바스크립트도 ES6에서는 extend 라는 키워드가 있으며, Class 간 상속을 지원합니다. 이는 사실 prototype 체인을 연결하는 구조입니다. 따라서 ES6 Class와 extend 키워드 없이도, 직접 prototype 속성을 사용해서 상속구조를 만들 수 있습니다. 좀 어려운 부분이지만 자바스크립트 prototype과 상속을 연관 지어서 학습해보면 좋습니다.
'부스트코스 웹 프로그래밍 > 5. 웹 앱 개발: 예약서비스 3' 카테고리의 다른 글
4. 상태유지기술(Cookie & Session) - BE (1) (0) | 2019.08.09 |
---|---|
3. form 데이터 보내기 - FE (2) (0) | 2019.08.09 |
3. form 데이터 보내기 - FE (1) (0) | 2019.08.09 |
2. JavaScript Regular expression - FE (0) | 2019.08.08 |
1. UI Component module - FE (1) (0) | 2019.08.08 |