[웹 풀스택] 부스트코스 - 웹 프로그래밍 - 3. 웹 앱 개발: 예약서비스 2/4

June·2021년 8월 5일
0

1. 객체지향 JavaScript구현 - FE

1) 배열의 함수형 메소드

for vs forEach

이런 데이터가 있다고 하겠습니다.

var data = [{title : "hello",content : "간지철철", price : 12000},
            {title : "crong",content : "괜춘한 상품", price : 5500},
            {title : "codesquad",content : "쩌는상품", price : 1200}];

for문과 forEach를 사용해보겠습니다.

for(var i=0; i<data.length; i++) {
  console.log(data[i].title , data[i].price)
}

data.forEach(function(v) {
   console.log(v.title, v.price);
});

forEach에서는 더 이상 i++이나 length를 판단하는 코드가 필요 없습니다.
그만큼 실수를 줄일 수 있고, 코드는 더 보기 좋습니다.

ES6의 arrow함수를 사용한다면 참고로 더 간단해집니다.

map

var newData = data.map(function(v) {
  return v.price * 1.1;
});
var newData = data.map(function(v) {
  var obj = {name : v.title, content: v.content, price: v.price* 10};
  return obj;
});

기존의 데이터는 바뀌지 않고 새로운 데이터를 반환한다.

var newData = data.filter(function(v) {
  return v.price > 5000;
});

filter를 이용해서 원하는 조건만 가져올 수 있다.

var newData = data.filter(function(v) {
  return v.price > 5000;
}).map(function(v) {
  var obj = {title: v.title, content: v.content, price: v.price+""};
  return obj;
});

체이닝이라는 것인데 반환값을 이용해서 또 한번 더 로직을 실행할 수 있다.

원본 데이터를 유지하자(immutable)

어떤 이유로 원본데이터가 변경되면, 추적도 어렵고, 어디서 어떤 이유로 변경된 것인지 좀 알기 어렵습니다.
또한, 때론 다시 이전 상태의 값을 되돌리고 싶을 경우도 있습니다.
원본 데이터를 유지하려면 어떻게 해야 할까요?

var filteredData = data.filter(function(v) {
    return v.price > 5000;
}).map(function(v) {
  var obj = {};
  obj.title = v.title;
  obj.content = v.content;
  obj.price = (''+v.price).replace(/^(\d+)(\d{3})$/, "$1,$2원");
  return obj;
});

원래의 data값은 그대로 유지되면서 새로운 배열만 확인할 수가 있습니다.
참고로 이를 immutable하다고 표현합니다.

reduce

reduce는 배열의 모든 요소에 대해 지정된 콜백 함수를 호출하며, 콜백 함수의 반환 값을 누적하여 반환하는 함수입니다.
reduce 함수의 매개변수로 콜백 함수와 누적을 시작하기 위한 초기 값이며 초기 값은 선택사항입니다.

var totalPrice = data.reduce(function(prevValue, product) { return prevValue + product.price; }, 0);

console.log(totalPrice);

위 코드는 redeuce를 사용하여 상품의 가격을 모두 합한 값을 반환하는 것을 확인하실 수 있습니다.
지금까지 몇개 낯선 메서드들을 알아봤습니다.
map, filter, forEach 이 3가지는 꼭 기억해주시기 바랍니다.

2) 객체 리터럴과 this

자바스크립트 객체의 활용

자바스크립트에서는 객체 리터럴이라는 표현식을 이용해 객체를 쉽게 만들 수 있습니다.
한 가지 비슷한 예제를 하나 살펴보겠습니다.

var healthObj = {
  name : "달리기",
  lastTime : "PM10:12",
  showHealth : function() {
    console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");
  }
}

healthObj.showHealth();

this라는 것은 실행 컨텍스트를 가리키므로, 실행시 결정된다.

this

객체 안에서의 this는 그 객체 자신을 가리킵니다.
참고로, ES6에서는 객체에서 메서드를 사용할 때 'function' 키워드를 생략할 수 있습니다.

const obj = {
   getName() {
     return this.name;
     },
  setName(name) {
      this.name = name;
    }
}
obj.setName("crong");
const result = obj.getName();

자바스크립트의 객체는 리터럴 (싱글톤)이다.

this 좀 더 알아보기

JavaScript에는 전역스크립트나 함수가 실행될 때 실행문맥(Execution context)이 생성됩니다.

(참고로 실제 실행은 브라우저내에 stack 이라는 메모리 공간에 올라가서 실행됩니다)

모든 context에는 참조하고 있는 객체(thisBinding이라 함)가 존재하는데, 현재 context가 참조하고 있는 객체를 알기 위해서는 this를 사용할 수 있습니다.

다시 말해, 함수가 실행될때 함수에서 가리키는 this 키워드를 출력해보면 context가 참조하고 있는 객체를 알 수 있습니다.

function get() {
    return this;
}

get(); //window. 함수가 실행될때의 컨텍스트는 window를 참조한다.
new get(); //object. new키워드를 쓰면 새로운 object context가 생성된다.

get()에서 this가 바뀌는 것을 알 수 있다. 지금은 this는 바뀔 수 있다라는 것까지만 이해하자.

3) bind메소드로 this제어하기

this 키워드는 this를 사용하고 있는 함수가 어떻게 불리는가에 따라서 달라지는 경우가 있습니다.
이때 그 함수의 context가 참고하는 객체를 원하는 것으로 바꾸고 싶을 수도 있습니다.

this가 달라지는 경우

showHealth는 어떤 이유인지 바로 출력하지 못하고, 1초 뒤에 결과를 출력하는 함수입니다. this가 무엇을 가리킬까요?

var healthObj = {
  name : "달리기",
  lastTime : "PM10:12",
  showHealth : function() {
    setTimeout(function() {
        console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");      
    }, 1000)
  }
}
healthObj.showHealth();

이 코드는 비동기 상황에서 일어나는 것으로, 이와 유사하게 비동기로 동작하는 이벤트 콜백에서 이런 일은 발생합니다.

(*참고로 es6의 arrow함수를 사용하는 경우 this가 가리키는 것이 또 다르니 이건 좀 당혹스러울 수 있습니다.)

bind method

bind 새로운 함수를 반환하는 함수입니다. 이부분이 좀 어색하고 혼란스러울 수 있습니다. bind동작은 특이하게도 새로운 함수를 반환한다는 점을 잘 기억해야 합니다.

bind함수의 첫번째 인자로 this를 주어, 그 시점의 this를 기억하고 있는 새로운 (바인드된)함수가 반환되는 것입니다.

var healthObj = {
  name : "달리기",
  lastTime : "PM10:12",
  showHealth : function() {
    setTimeout(function() {
        console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");      
    }, 1000)
  }
}
healthObj.showHealth();

실행을 해보면 this.name이 undefined로 나온다. 왜냐하면 저기서 this는 실행중인 함수를 가리키기 때문이다.

var healthObj = {
  name : "달리기",
  lastTime : "PM10:12",
  showHealth : function() {
    setTimeout(function() {
        console.log(this.name + "님, 오늘은 " + this.lastTime + "에 운동을 하셨네요");      
    }.bind(this), 1000)
  }
}
healthObj.showHealth();

위 예제에서 객체리터를 표기법을 사용했으며, ES6(ES2015)부터는 객체에서 메서드를 사용할 때 'function' 키워드를 생략할 수 있습니다.

그래서 setTimeout안에 있다하더라도 this가 '나'를 가리키게 하려면 bind를 통해서 써줘야한다. 함수의 바깥 부분에서 bind(this)가 쓰였는데, 그러면 showHealth가 실행되는 공간을 뜻한다.

함수 뒤에 점을 붙이는 순간, 객체로 변하기 때문에 가능한 것이다. function native 메서드를 호출하는 것이다.

.bind()는 this를 바인딩한 새로운 함수를 반환하는 것이다.

arrow function에서는 this가 컨텍스트를 유지하면서 작동하므로 bind를 따로 안써줘도 된다.

bind는 많은 정보를 담고 있다. 펑션이 객체로 동작되는 것을 알려주고, 함수를 반환하는 함수라는 것도 알려주고, this가 가리키는 것을 바꿔준다.

2. 라이브러리 활용과 클린코드 - FE

1) JavaScript 라이브러리

jQuery 의 10년

지난 10년간, JS라이브러리는 jQuery가 그 인기를 독차지했었습니다.

2018년 현재 그 인기는 많이 줄었습니다.

어떤 이는 이제 더 배울 필요가 없다고 이야기되고 합니다.

(실제로는 기존에 적용된 코드를 수정하느라 웹개발자들이 쉽게 jQuery를 떠날 수는 없을 겁니다.)

jQuery가 인기 있던 이유는 꽤 많은데요, 몇 가지 꼽으면 다음과 같습니다.

  • IE6,7,8를 포함해서 다양하게 동작하는 웹브라우저의 API 간의 차이를 줄여주었습니다.
  • 복잡하고 어려운 DOM APIs를 추상화해서 제공해서 쉽게 DOM 조작이 가능합니다.
  • 사고의 흐름에 맞춰 프로그래밍할 수 있습니다.

jQuery에서 DOM조작을 어떻게 처리하는지 찾아보면 꽤 편리합니다.

물론 그전에 DOM을 native방식으로 접근해야, jQuery가 얼마나 편리한지 알겠지만요.

아래 코드는 '사고의 흐름'이라는 관점에서 이해할 수 있는 jQuery코드 입니다.

//p1아이디를 가진 엘리먼트를 찾아서, color를 red 로 하고, slideup을 2초간, slideDown을 2초간 한다.
$("#p1").css("color", "red").slideUp(2000).slideDown(2000); 

주석에 적힌 내용대로 코드를 그대로 구현할 수 있습니다.

메서드를 연속적으로 부르는 방식을 method chaining이라고 합니다.

이러한 방식은 jQuery뿐만 아니라 많은 라이브러리에서 제공하고 있습니다.

그러던 jQuery가 왜..

인기 있던 이유를 하나씩 현재 다시 보면 이렇습니다.

  • 점차 브라우저 호환성 이슈가 줄었습니다.
  • DOM APIs는 그대로지만, 7~8년 전부터 등장한 JS Frameworks 들이 좀 더 추상화된 방식으로 DOM 접근을 도와주고 있습니다.
  • 다른 라이브러리들도 이런 방식을 지원도 합니다.

그 외에도 ECMAScript 2015부터 편리한 함수들이 많이 제공되고 있습니다.

jQuery가 제공했던 유용한 기능들이 JavaScript표준방법으로 사용할 수 있게 된 것이죠.

Framework

이야기는 좀 깁니다.

짧게 요약하면 웹에서 할 수 있는 것들이 많아지면서, Single Page Application이라는 서비스개념이 등장했습니다.

즉 웹에서 데이터처리나 복잡한 Ajax처리, routing처리 등이 많아지면서, 이를 편리하게 해주는 Framework가 나왔습니다.

React, Angular, Vue, Ember와 같은 것들이 그런 것입니다.

이를 사용하면 좀 더 쉽게 DOM제어를 할 수 있고, Data조작을 View에서 분리해서 관리할 수 있습니다.

그리고 component방식으로 개발할 수 있어 재사용가 능한 코드를 만들 수도 있고요.

라이브러리가 유용한 함수들을 제공한다고 할 수 있다면, Framework는 큰 애플리케이션의 구조를 잡는 것을 도와주는 역할을 하죠.

특히 데스크탑 웹 개발에서 더 유용하게 사용할 수 있습니다.

그 밖에

라이브러리 수준에서 유용한 것들은 이제는 Framework에서 이를 얼마나 사용하는가에 의해서 인기가 달라집니다.

다시 말해서, '어떤 Framework가 인기가 있는가?'에 의해서 그 Framework이 가진 철학에 따라서 필요한 라이브러리가 의존적으로 많이 쓰이고 인기를 얻고 있습니다.

그렇다보니, Framework과 관련 없이 많이 쓰일만한 라이브러리는 이제 별로 없습니다.

Observables을 처리해주는 RxJS나, Lodash와 같은 데이터를 쉽게 처리해주는 유틸리티 등이 인기를 얻는 정도입니다.

나머지 라이브러리는 해당 Framework가 사용하는 것이 무엇인가에 따라 달라집니다.

예를 들어 React에서는 Immutable.js나 Redux 등이 인기를 얻고 있는 것처럼요.

jQuery를 사용해야 한다면,

많은 웹서비스의 legacy코드는 아직도 jQuery나 오래된 라이브러리를 사용합니다.

당분간 이를 유지 보수해야 하는 개발자는 상당히 많을 것입니다.

jQuery를 다뤄야 할 때는 몇 가지 가이드를 기억해두면 좋습니다.

jQuery의 버전을 잘 확인하고, 그 버전에 맞는 적절한 메서드를 선택합니다.

한 페이지에 여러 가지 jQuery버전이 없도록 합니다.

가급적 대체 가능한 메서드는 표준 JavaScript메서드를 사용하면서 jQuery의존도를 줄여나갑니다.

결론

라이브러리나 프레임워크는 필요한 시점에 적절한 것을 골라서 사용하면 됩니다.

그리기 위해서는 라이브러리나 프레임워크가 어떤 목적을 가지고 있는 것인지 관심을 두는 게 좋습니다.

그래야 우리에게 필요한 것을 잘 선택할 수 있습니다.

어쩌면 라이브러리가 필요하지 않은 경우도 상당히 많습니다.

2) handlebar를 활용한 템플릿 작업-1

templating작업은 ES2015에서 template literal로 좀 더 간단해지긴 했습니다.
하지만 여전히 다양한 조건 상황에서의 처리 등은 여전히 복잡합니다.
templating 작업을 돕는 라이브러리는 꽤 다양하고 막강한 방법을 제공합니다.
이를 사용해보면서 templating 처리의 세련된 방법을 알아두면 좋습니다.
더구나 아직도 많은 legacy코드는 template 라이브러리를 사용하는 경우가 많습니다.

기본 예제

html에 다음과 같이 template코드를 만듭니다

<script type="myTemplate" id="listTemplate">
	<li>
     <div>게시자 : {{name}}</div>
     <div class="content">{{content}}</div>
     <div>좋아요 갯수 <span> {{like}} </span></div>
     <div class="comment">
       <div>{{comment}}</div>
     </div>
  </li>
</script>	

javascript에서는 replace로 치환하는 방법 말고, 라이브러리를 사용해서 결과를 얻을 수 있습니다.

https://cdnjs.com/libraries/handlebars.js

var template = document.querySelector("#listTemplate").innerText;
var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.

이제 데이터를 추가합니다.

var data = {
  	"id" : 88,
    "name" : "crong",
    "content" : "새로운글을 올렸어요",
    "like" : 5, 
    "comment" : "댓글이다"
};

bindTemplate(data);

demo.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>template using handlebar</h1>

    <section class="show">

    </section>

    <script type="myTemplate" id="listTemplate">
        <li>
         <div>게시자 : {{name}}</div>
         <div class="content">{{content}}</div>
         <div>좋아요 갯수 <span> {{like}} </span></div>
         <div class="comment">
           <div>{{comment}}</div>
         </div>
      </li>
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
    <script>
        var data = {
            "id" : 88,
            "name" : "crong",
            "content" : "새로운글을 올렸어요",
            "like" : 5, 
            "comment" : "댓글이다"
        };

        var template = document.querySelector("#listTemplate").innerText;
        var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.
        var resultHTML = bindTemplate(data);
        var show = document.querySelector(".show");
        show.innerHTML = resultHTML;
    </script>
</body>
</html>

데이터를 바인드할때 {{}}를 기준으로 데이터를 바인드한다.

2) handlebar를 활용한 템플릿 작업-2

templating작업은 ES2015에서 template literal로 좀 더 간단해지긴 했습니다.

하지만 여전히 다양한 조건 상황에서의 처리 등은 여전히 복잡합니다.
templating 작업을 돕는 라이브러리는 꽤 다양하고 막강한 방법을 제공합니다.
이를 사용해보면서 templating 처리의 세련된 방법을 알아두면 좋습니다.
더구나 아직도 많은 legacy코드는 template 라이브러리를 사용하는 경우가 많습니다.

배열이 포함된 데이터의 처리

예를 들어 comment 1개 이상일 수 있습니다.

var data = {
  	"id" : 88,
    "name" : "crong",
    "content" : "새로운글을 올렸어요",
    "like" : 5, 
    "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]
};

bindTemplate(data);

이런 경우는 이렇게 반복문을 넣을 수도 있습니다.
each 부분을 눈여겨보세요.

<script type="myTemplate" id="listTemplate">
    <li>
        <div>게시자 : {{name}}</div>
        <div class="content">{{content}}</div>
        <div>좋아요 갯수 <span> {{like}} </span></div>
        <div class="comment">
        <h3>댓글목록</h3>
        {{#each comment}}
            <div>{{@index}}번째 댓글 : {{this}}</div>
        {{/each}}
        </div>
    </li>
</script>	

샾을 붙이면 헬퍼기능을 호출한다. 여기서는 /each를 만날때까지 #each 토큰을 반복한다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>template using handlebar</h1>

    <section class="show">

    </section>

    <script type="myTemplate" id="listTemplate">
        <li>
            <div>게시자 : {{name}}</div>
            <div class="content">{{content}}</div>
            <div>좋아요 갯수 <span> {{like}} </span></div>
            <div class="comment">
            <h3>댓글목록</h3>
            {{#each comment}}
                <div>{{@index}}번째 댓글 : {{this}}</div>
            {{/each}}
            </div>
        </li>
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
    <script>
        var data = {
            "id" : 88,
            "name" : "crong",
            "content" : "새로운글을 올렸어요",
            "like" : 5, 
            "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]
        };

        var template = document.querySelector("#listTemplate").innerText;
        var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.
        var resultHTML = bindTemplate(data);
        var show = document.querySelector(".show");
        show.innerHTML = resultHTML;
    </script>
</body>
</html>

data자체가 많아진 경우의 처리

그런데, 실제 데이터는 좀 더 많을 것입니다.

var data = [
	{"id" : 88, "name" : "crong", "content" : "새로운글을 올렸어요", "like" : 5, "comment" : ["댓글이다", "잘했어요"]},
	{"id" : 28, "name" : "hary", "content" : "전 오늘도 노래를 불렀어요", "like" : 0, "comment" : ["제발고만..","듣고싶네요 그노래"]},
	{"id" : 23, "name" : "pororo", "content" : "크롱이 항상 말썽을 피워서 행복해~", "like" : 4, "comment" : []},
	{"id" : 5, "name" : "pobi", "content" : "물고기를 한마리도 잡지 못하다니..", "like" : 5, "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]}
];

반복적으로 결과를 forEach 또는 reduce를 사용해서 합칠 수 있습니다.

forEach

var innerHtml = "";

data.forEach(function (item, index) {
	innerHtml += bindTemplate(item);
});

reduce

var innerHtml = data.reduce(function(prve, next) {
	return prve + bindTemplate(next);
}, "");

demo.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>template using handlebar</h1>

    <section class="show">

    </section>

    <script type="myTemplate" id="listTemplate">
        <li>
            <div>게시자 : {{name}}</div>
            <div class="content">{{content}}</div>
            <div>좋아요 갯수 <span> {{like}} </span></div>
            <div class="comment">
            <h3>댓글목록</h3>
            {{#each comment}}
                <div>{{@index}}번째 댓글 : {{this}}</div>
            {{/each}}
            </div>
        </li>
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
    <script>
        var data = [
            {"id" : 88, "name" : "crong", "content" : "새로운글을 올렸어요", "like" : 5, "comment" : ["댓글이다", "잘했어요"]},
            {"id" : 28, "name" : "hary", "content" : "전 오늘도 노래를 불렀어요", "like" : 0, "comment" : ["제발고만..","듣고싶네요 그노래"]},
            {"id" : 23, "name" : "pororo", "content" : "크롱이 항상 말썽을 피워서 행복해~", "like" : 4, "comment" : []},
            {"id" : 5, "name" : "pobi", "content" : "물고기를 한마리도 잡지 못하다니..", "like" : 5, "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]}
        ];

        var template = document.querySelector("#listTemplate").innerText;
        var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.
        
        var resultHTML = data.reduce(function(prev, next) {
            return prev + bindTemplate(next);
        }, "");
        
        var show = document.querySelector(".show");
        show.innerHTML = resultHTML;
    </script>
</body>
</html>

조건 상황에 따른 처리

지금 예제에서 댓글이 없는 경우에는 다른 메시지를 처리해야 한다면 어떨까요?
template은 말 그대로 고정되어 있는 것이죠.
하지만 handlebar에서는 이를 지원하네요.

<script type="myTemplate" id="listTemplate">
    <li>
        <div>게시자 : {{name}}</div>
        <div class="content">{{content}}</div>
        <div>좋아요 갯수 <span> {{like}} </span></div>
        <div class="comment">
        <h3>댓글목록</h3>
        {{#if comment}}
            {{#each comment}}
                <div>{{@index}}번째 댓글 : {{this}}</div>
            {{/each}}
        {{else}}
            <div>댓글이 아직 없군요</div>
        {{/if}}
        </div>
    </li>
</script>

demo.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>template using handlebar</h1>

    <section class="show">

    </section>

    <script type="myTemplate" id="listTemplate">
        <li>
            <div>게시자 : {{name}}</div>
            <div class="content">{{content}}</div>
            <div>좋아요 갯수 <span> {{like}} </span></div>
            <div class="comment">
            <h3>댓글목록</h3>
            {{#if comment}}
                {{#each comment}}
                    <div>{{@index}}번째 댓글 : {{this}}</div>
                {{/each}}
            {{else}}
                <div>댓글이 아직 없군요</div>
            {{/if}}
            </div>
        </li>
    </script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.7/handlebars.min.js"></script>
    <script>
        var data = [
            {"id" : 88, "name" : "crong", "content" : "새로운글을 올렸어요", "like" : 5, "comment" : ["댓글이다", "잘했어요"]},
            {"id" : 28, "name" : "hary", "content" : "전 오늘도 노래를 불렀어요", "like" : 0, "comment" : ["제발고만..","듣고싶네요 그노래"]},
            {"id" : 23, "name" : "pororo", "content" : "크롱이 항상 말썽을 피워서 행복해~", "like" : 4, "comment" : []},
            {"id" : 5, "name" : "pobi", "content" : "물고기를 한마리도 잡지 못하다니..", "like" : 5, "comment" : ["댓글이다", "멋진글이네요", "잘봤습니다"]}
        ];

        var template = document.querySelector("#listTemplate").innerText;
        var bindTemplate = Handlebars.compile(template);  //bindTemplate은 메서드입니다.
        
        var resultHTML = data.reduce(function(prev, next) {
            return prev + bindTemplate(next);
        }, "");
        
        var show = document.querySelector(".show");
        show.innerHTML = resultHTML;
    </script>
</body>
</html>

2) handlebar를 활용한 템플릿 작업-3

참고

Help function사용 좀 더 다양한 상황을 처리해야 한다면, help function을 통해서 처리할 수도 있습니다.
좋아요 갯수가 5개 이상이면 "축하해요. 좋아요가 5개이상 입니다"라는 문자열을 추가해보겠습니다.
먼저 template을 살펴보면 다음과 같습니다.
likes라는 커스텀 항목을 추가했어요.

<script type="myTemplate" id="listTemplate">
    <li>
        <div>게시자 : {{name}}</div>
        <div class="content">{{content}}</div>

        {{#likes like}}
            {{like}}
        {{/likes}}

        <div class="comment">
        <h3>댓글목록</h3>
        {{#if comment}}
            {{#each comment}}
                <div>{{@index}}번째 댓글 : {{this}}</div>
            {{/each}}
        {{else}}
            <div>댓글이 아직 없군요</div>
        {{/if}}
        </div>
    </li>
</script>

이제 다양항 조건을 설정하는 likes helper를 만들 겁니다.

#likes라는 함수가 없으니 만든 함수가 있는지 찾아간다.

 Handlebars.registerHelper("likes", function (like) {
    if (like > 4) {
        return "<span>축하해요 좋아요가 " + like + "개 이상입니다!</span>";
    } else if (like < 1) {
        return "아직 아무도 좋아하지 않아요..";
    } else {
        return like + "개의 좋아요가 있네요";
    }
});

likes라는 이름으로 함수를 등록하고 있다. 반환 결과값이 {{#likes like}}, {{/likes}} 사이에 들어간다.

Helper 함수는 템플릿 처리를 좀 더 유연하게 처리할 수 있게 돕습니다.
그 사용법이 막강한 만큼 나중에 잘 활용하면 좋습니다.

3) 클린코드

이름 (코딩컨벤션)

이름을 짓는 건 쉬운 일은 아니지만, 읽기 좋은 코드를 만드는데 필수 요소입니다.
이런 부분을 고려하세요.

  • 함수는 목적에 맞게 이름이 지어져 있는가?
  • 함수 안의 내용은 이름에 어울리게 하나의 로직을 담고 있는가?
  • 함수는 동사 + 명사이며 함수의 의도를 충분히 반영하고 있는가?
  • 함수는 카멜표기법 또는 _를 중간에 사용했는가?
  • 변수는 명사이며 의미 있는 이름을 지었는가?

의도가 드러난 구현패턴

어떤 코드가 좋은지 고민이라면, 내 코드를 들여다보고 그 의도가 잘 보이는지 확인해봅니다.
예를 들어, var a = value * 19.2; 이라는 코드가 있다고 봅시다.
도대체 19.2가 무엇을 의미하는지? 알 수가 없습니다.
대신 변수로 저장하고, 변수에 적절한 이름을 쓰면 더 좋습니다.

지역변수로 넣으면 될 걸 전역공간에 두지 말기

함수 내에서만 사용이 필요로 한 것은 지역변수로 만들어야 합니다.
불필요한 전역변수는 최소화해야 코드가 많아지고 수정할 때 복잡함을 줄일 수 있습니다.

var a = 'hello';

function print() {
   return data;
}

function exec() {
   var data = "world";
   a = a + " ";
   print(a + data)
}

빨리 반환해서 if문 중첩 없애기

아래 코드는 중복된 if문을 어떻게 개선할 수 있나요?

function foo(pobi,crong) {
  if(pobi) { 
    if(crong) {
      return true;
    }
  }
}

if문을 아래처럼 한다면 쉽게 중첩된 코드를 없앨 수 있습니다.
return문을 잘 쓰세요.

function foo(pobi,crong) {
  if(!pobi) return;
  if(crong) {
    return true;
  }
}

전역변수를 줄이자

자바스크립트에서 var키워드를 함수 안에서 사용하면, 그 변수는 함수안에서만 유용합니다.
이를 함수 scope라고 합니다.
하지만 함수 안에서 var 키워드를 사용하지 않으면 전역변수가 됩니다.
물론 함수 밖에서 var 키워드를 사용해서 변수를 선언해도 이건 전역변수입니다.

다양한 함수에서 같이 어떤 값을 공유하면서 사용해야 한다면 전역변수로 두고 쓸 수 있습니다.
이는 전역공간을 더럽히는 것으로 나중에 디버깅이 어려울 수 있습니다.

정적 분석 도구

eslint와 같은 도구는 코드를 읽어서 잠재적인 문제와 anit-pattern을 알려줍니다.
이는 개발도구에서도 plugin을 연동해서 활용할 수가 있습니다.
내 코드가 어떤 문제가 없는지 확인해보세요.

0개의 댓글