티스토리 뷰

2) 생성자패턴으로 TabUI만들기

이전의 Tab UIprototype을 활용하여 객체를 만드는 클래스 형태의 코드로 만들어보겠습니다.

자바스크립트 객체 다시 이해하기

  • 전역공간에 구현된 코드를 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() thisprototype에 있는 객체를 가리킬 수가 있어서 메서드들이 실행될 겁니다.
  • 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 tabmenudependency가 있는건데 인자로 받으면 dependency가 사라집니다. function Tab(tabElement) { this.tabmenu = tabElement 이렇게 써주면 tabmenu tabElement가 디폴트로 들어가는 거예요. 그러면 의존성이 없어진 코드가 되는 겁니다.
  • 이런 식으로 하나의 Tab 클래스를 메서드를 여러 개 넣으면서 만들 수가 있습니다.

생각해보기

  • 자바스크립트도 ES6에서는 extend 라는 키워드가 있으며, Class 간 상속을 지원합니다. 이는 사실 prototype 체인을 연결하는 구조입니다. 따라서 ES6 Class extend 키워드 없이도, 직접 prototype 속성을 사용해서 상속구조를 만들 수 있습니다. 좀 어려운 부분이지만 자바스크립트 prototype과 상속을 연관 지어서 학습해보면 좋습니다.

 

Comments