: 출처 : 문학청년 블로그

개요

콜백(Callback)이란 디자인 패턴 중 하나인 옵저버(Observer) 패턴에서 나온 개념으로써 객체의 상태 변화(이벤트)가 발생 하였을 경우에 이러한 사실을 함수를 통해 전달하게 되는데, 이를 콜백 함수라고 한다. 자바스크립트에서 콜백 함수는 키보드나 마우스 클릭과 같은 디바이스 이벤트 뿐만이 아니라 Ajax, 데이터 처리 등 많은 부분에서 사용되고 있다.

이번 강좌에서는 콜백 함수의 기본적인 사용 방법과 좀 더 활용할 수 있는 방법에 대해 알아볼 것이다.
 

기초

출근을 위해 반드시 오전 8시에 일어나야 한다고 가정해보자. 그렇다면 어떻게 일어나야 할까? 첫 번째 방법으로는 생각날 때마다 현재 시간을 확인하는 것이다. 하지만 이 방법은 매우 좋지 않다. 수 없이 현재 시간을 확인해야 될 뿐더러 계속 신경써야 하기 때문에 쉽게 피곤해질 수 있다. 만약에 오전 8시를 알려주는 알람 시계가 있다면 이러한 문제는 해결된다. 주기적으로 현재 시간을 확인하지 않아도 되기 때문에 신경쓰지 않고 푹 잘 수 있다.

콜백 함수는 시계의 알람 기능과 비슷하다고 생각하면 이해하기가 조금 더 쉬울 것이다. (Link)

위의 예제에 정의된 alram 함수는 사용자가 정한 Minutes에 알림 메시지를 보여주는 함수이다. 콜백 함수는 특정 기능을 수행하기 위한 로직과 기능 수행 후 반환되는 결과 값을 가지고 이를 표현하는 로직을 서로 분리 할 수 있다. 이는 뷰(View)의 분리라는 점에서 MVC 패턴과 비슷하다고 볼 수 있다.

최근에 대세가 되버린 jQuery 라이브러리에서 제공하는 많은 함수들의 결과 값이 콜백 형태로 호출된다. 이런 함수들은 이벤트 처리, 애니메이션, Ajax, 콜렉션 등에서 사용된다. 콜백으로 결과 값을 반환하는 함수들은 공통적인 특징이 하나 있는데, 그것은 바로 뷰(View)를 처리하는 시점이 모호하다는 것이다.

 위의 예제를 실행해보면 undefined 값이 출력 된다. $.getJSON 함수가 먼저 호출되더라도 결과 값은 alert 함수보다 늦게 가져오기 때문에 undefined 값이 출력되는 것이다. 물론 약간의 시간 차이를 두어 값을 받을 수도 있다.

 하지만 모두 시간 차이를 두어서 구현할 수는 없다. 가독성이 떨어질 뿐더러 Ajax 호출의 경우 네트워크 상황에 따라 값을 제대로 가지고 오지 못하는 경우도 발생할 수 있다.
 

심화

특정 함수의 반환 값을 콜백으로 넘기는 방법은 위의 예제들을 보면 알 수 있듯이 그렇게 어렵지 않다. 매개 변수를 통해 함수를 받고, 그 함수를 통해 결과 값을 다시 호출하면 되기 때문이다. 하지만 jQuery에서 제공되는 함수들을 보면 단순히 콜백을 통해 결과 값을 넘기지 않는다.

jQuery $.each 함수는 해당 배열의 요소들을 모두 순환하면서 콜백으로 index 값을 넘기는데 이 요소를 콜백 함수의 매개 변수로 넘기지 않고 함수 내에서 this 키워드로 접근한다.

위의 예제를 보면 this 키워드를 통해 test 배열에 포함되어 있는 요소(객체)들을 접근하고, name이란 프로퍼티를 출력하였다. 하지만 어떻게 콜백 함수 안에서 this 키워드를 사용하여 name 프로퍼티를 출력할 수 있었을까?

답을 말하기에 앞서 우선 아래 예제를 보자. (Link)

위의 함수는 매개 변수로 받은 배열을 순차적으로 접근하여 콜백을 통해 각각의 배열 요소들을 넘겨주는 함수를 구현한 것이다. 하지만 현재 위치의 요소를 콜백 함수의 파라메터로 넘겼을 뿐, 콜백 함수 내에서 this로 접근하지는 못한다.

그럼, 콜백 함수 내에서 this 값이 무엇이 찍히는지 확인해보자.

위의 예제를 실행해보면 “[object Window]“라는 메시지가 3번 출력될 것이다. 자바스크립트에서 함수는 정의될 때, 기본적으로 Window 객체의 메소드가 되기 때문에 콜백 함수 내에서 this는 Window 객체가 되는 것이다.

그렇다면 콜백 함수 내에서 배열 요소를 this로 접근하기 위해서는 어떻게 해야 될까? 먼저 이전 강좌에서 다룬 prototype를 사용하여 콜백 함수의 원형을 배열 요소로 변경해주면 된다.

자바스크립트 함수는 클래스이며 자신의 원형을 prototype로 정할 수 있다. 즉, 매개 변수를 통해 받은 콜백 함수는 name 프로퍼티를 가진 객체 자체가 되는 것이다. 하지만 prototype으로 자신의 원형을 해당 배열 요소로 정했다고는 하지만 단순한 콜백 함수 호출로는 콜백 함수 내에서 this 키워드로 접근 할 수 없다.

왜냐하면 자바스크립트 함수는 앞서 말한 것처럼 기본적으로 Window 객체이기 때문이다. 그렇다면 자신만의 고유한 객체가 되기 위해선 어떻게 해야 될까? 그건 바로 new 키워드를 사용하면 된다.

 이유를 설명하기에 앞서 아래 예제를 보자.

위의 예제의 출력 메시지는 “test1 : [object Window]“, “test2 : [object Object]“이다. 앞서 말한 것처럼 자바스크립트 함수는 클래스이기도 하기 때문에 고유한 객체(인스턴스)를 생성할 수 있다. 즉, new 키워드를 사용하여 콜백 함수를 호출하면 Window 객체가 아닌 새로운 객체가 되는 것이다. 단순하게 new 키워드 사용 유무를 “non-static / static” 개념이라고 생각하면 이해하기 쉬울 것이다. 
(본 강좌에서는 static에 대한 설명은 하지 않겠음)

마지막으로 아래 예제는 이때까지 고대해왔던 완성된 each 함수이다. (Link)

 

자바스크립트에서 조건문을 쓸 때


일반적으로 if 문 안에 true,또는 false가 올 만한


값을 넣고 사용을 한다.


하지만 자바스크립트가 허용해주는 예외가 있다.


그것은 바로 0, undefined, NaN, null , ''(빈문자열), [](빈 배열) 등 무언가 공백이나 오류를 의미하는 값은 false로 인식,


 값이 있는 상수, 값이 있는 변수 등은 true로 인식한다. 


예컨대 


if (3)

{
}


는 항상 실행되는 문장이다.


이 사실을 어떻게 활용할수 있을까?

첫번째로는 값의 존재 유무를 체크하는 것이다.


예컨대 

if (document.getElementById('test'))

{

}


라 하면, "document 상에 test라는 아이디를 가진 엘리먼트가 존재하면 중괄호내 문장을 실행"이


라는 의미가 되는것이다.


또한가지는, 우리가 흔히 사용하는


return;, 또는 return 0;


이라는 문장. 보통은 이 문장을 기점으로 이벤트를 중지시키려고 사용하지만,


return false; 가 좀더 명시적이고 올바른 표현이다.


return 0, return이 분명 자바스크립트 상에서 return false와 비슷한 효과를 주긴 하지만, 


진정한 프로그래머라면 코드의 가독성을 높이는 명시적인 코딩을 해야하지 않을까?

핸드폰번호, 신용카드 등의 입력 값 중 -를 제거 할 때,


단순히 replace('-','')를 하게 되면, 최초의 - 기호만 삭제되고 이후의 기호는 삭제되지 않습니다.


전체 문자열에서 특정 문자를 제거하고 싶다면 아래와 같이 사용할 수 있습니다.



var value = ' 02 - 1234 - 5678 ';

value = value.replace(/\-/g,''); //특정문자 제거

value = value.replace(/^\s+/,''); //앞의 공백 제거

value = value.replace(/\s+$/,''); //뒤의 공백 제거

value = value.replace(/^\s+|\s+$/g,''); //앞뒤 공백 제거

value = value.replace(/\s/g,''); //문자열 내의 공백 제거

value = value.replace(/\n/g,''); //개행 제거

value = value.replace(/\r/g,''); //엔터 제거


//value : 0212345678


 


// 0 제거 

var value = '001002003004005006'

var result = value.replace(/[^(1-9)]/gi,"");




* 당첨번호 / 총번호 : 랜덤으로 뽑기 (중복제거)*

* 결과값인 배열을 하나씩 시간지연 출력 *

 

<!DOCTYPE html>
<html>
 <head>
  <title>번호추첨</title>
  <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
  <meta content="utf-8" http-equiv="encoding">
  <script type="text/javascript" src="/scripts/jquery-1.10.2.min.js"></script>
  <link type="text/css" href="/css/design.css" rel="stylesheet" />
<style type="text/css">
body
{
 background-image:url('/images/bglotto.jpg');
 background-repeat:no-repeat;
 background-attachment:fixed;
}
</style>  
  
<script type="text/javascript">

 

/* 배열에 랜덤값 얻기 */

 function shuffleRandom(){
      $("#resultBox").empty();
      $("#resultBox2").empty();
      $("#resultBox3").empty();
 
 // 결과 담을 배열

 var resultArray = [];  
 var n = $("#resultMax").val();  // 당첨자수
    var total = $("#total").val();   // 총인원
    var temp;          // 난수 임시로 담을 변수
    var dupCheckFlag = 0;     // 중복체크 Flag (0,1)

 

  for(var i = 0; i < n ; i++){    // 필요한 당첨자수 많큼 루프
 
  temp = Math.floor(Math.random() * total) + 1;  // 난수 생성 (+1 은 0 제외)

     for(var y = 0; y < i ; y++){      //  기존 배열 값들 0 부터 i 번째(현재) 전까지
      if(resultArray[y] == temp){        // 중복체크 _ 같은것이 있다면,
       i = i - 1;           //  현재 배열위치 i 에서 한칸 앞 위치를 가져간다. *( i++ 가 되니 미리 i-1해준다.) 결국은 i값이 증가되지 않는것.
       dupCheckFlag = 1;      //  배열에 값을 넣지 않기 위해 중복체크 플래그 값 설정해주고
      }
     }             

     if(dupCheckFlag == 0){     // 중복된 값이 아니면 난수를 배열 i 번째 넣어주고.
      resultArray[i] = temp;
     } else {
      dupCheckFlag = 0;      // 중복된 값이면 i -1 번째 그대로 간다.
     }
    }
 
  for(var k = 0; k < n ; k++){    // * 화면 출력시 10명씩 한줄에 & setInterval 시간지연 .. 번호 하나씩 출력
       fn_view(resultArray[k], k);    //(결과값, 순서)

  }

} // end of shuffleRandom


function fn_view(p,k){

var x = 1000;        //  setInterval 시간계산용 ms

 

    if(k < 10){        // 첫번째 줄. 1~10개까지
     var varTimer = setInterval(function(){         // ***시간지연 함수
        $("#resultBox").append(p);
       if(k !=9){
        $("#resultBox").append(" , ");
     }
     clearTimeout(varTimer);             // setInterval() 메소드의 작동을 정지하기 위해서 clearInterval() 메소드를 사용한다.
    }, x*k);                    //  ***지연시간 Set ( 1000 *  k 가 순번 증가값이므로 지연시간이 1초씩 늘어난다. )
      } else if(k <20){
     var varTimer = setInterval(function(){
         $("#resultBox2").append(p);
        if(k !=19){
         $("#resultBox2").append(" , ");
      }
      clearTimeout(varTimer);
     },x*k);
     } else{
     var varTimer = setInterval(function(){
        $("#resultBox3").append(p);
        if(k !=29){
       $("#resultBox3").append(" , ");
      }
      clearTimeout(varTimer);
     },x*k);
     }

} //end of fn_view

 

</script>

</head>

<body>
<div style="font-size: 20px">
 <p style="font-size: 40px;margin-left: 100px; margin-top: 50px;color: white">오픈스마트 플랫폼 경품 추첨</p>
<div style="margin-top: 100px">
     <span style="margin-left: 50px;color: white"> 참석자수:</span><input type="text" id="total" />
     <span style="margin-left: 30px;color: white"> 당첨인원:</span><input type="text" id="resultMax"/>
     <input type="button" id="lottoResult" value="추첨하기" style="margin-left: 20px" onclick="shuffleRandom()"/>
</div>
    <div id="resultBox" style="font-size: 30px; margin-left: 50px; margin-top: 60px;color: white"></div>
    <div id="resultBox2" style="font-size: 30px; margin-left: 50px; margin-top: 25px;color: white"></div>
    <div id="resultBox3" style="font-size: 30px; margin-left: 50px; margin-top: 25px;color: white"></div>

</div>
</body>
</html>

 

 

+ Recent posts