콜백은 단어 뜻 자체가 '회신하다/답신하다'라는 뜻을 지닌다.
그렇다면 콜백 함수는 회신되는 함수라고 할 수 있겠다.
쉽게 설명하자면 함수를 누군가한테 처리해달라고 부탁하면 누군가는 함수를 처리하고 다시 돌려주는 형태이다.
즉, 함수에 대해 제어권을 위임하는 것이다.
setInterval은 일정 시간 간격으로 한번씩 함수를 실행해주는 함수이다.
주기함수인 setInterval을 호출하면 맨 처음 콜백함수가 실행된다.
그 다음 위의 화면과 같이 인자2를 실행해준다.
이때 1000은 1000ms로 0.01초를 뜻한다.
위와같이 setInterval에 callback함수인 cb를 넘겨주면 setInterval이 cb에 대해 제어권을 가진다.
즉, setInterval이 알아서 milliseconds주기마다 cb를 실행시키는 것이다.
넘겨줄수 있는 제어권에는 '매개변수' 도 있다.
위의 forEach는 배열에 있는 요소들을 순서대로 하나씩 꺼내고 인자2에는 index번호를 부여한다.
위의 결과값을 보면 여기서 this가 뭔진 잘 모르겠지만 배열의 [0]에 10이 [1]이 20이 나오는 것을 보면 [10, 20, 30, 40, 50] 배열에서 나오는 것을 알 수 있다.
즉, forEach(callback[, thisArg]) 로 이루어져 있다.
이때 thisArg는 생략이 가능하다.
즉, forEach를 호출하면 인자1인 콜백함수가 실행되고, 인자2인 thisArg는 콜백을 실행할때 this로서 사용한는 값이 된다.
여기서 알수있는 점은 forEach가 정의한대로 값을 넣어야만 제대로 된 동작을 실행할 수 있다는 점이다.
위의 사진처럼 내가 콜백함수의 첫번째 매개변수를 index로 하고싶다고 index의 값이 나오는게 아니다. 그저 index이름의 arr의 value값이 나올 뿐이다.
this도 제어권을 넘길 수 있는 대상 중의 하나이다.
위의 사진처럼 addEventListener함수를 이용해 콜백함수인 cbFunc를 실행하면 어떻게 될까?
this에는 클릭한 대상인 id가 a인 div가 나온다.
x의 값은 PointerEvent라고 해서, click event에 대한 객체가 나왔다.
이것의 이유는 addEventListener가 콜백함수를 받을때 this는 eventTarget으로 하고, 콜백함수의 첫번째 인자에는 event 객체를 넘겨주도록 정해놓았기 때문이다.
마지막은 firefox에서만 작동하는 거라서, 위의 두개만 설명하겠다.
첫번째 인자는 type이 온다.
type에는 click, mousemove, keyup 등등 이벤트 이름에 해당하는 문자열이 온다.
그다음으로 listener.
ECMAScript 명세서에는 callback이라고 명시되어 있으나 MDN에서는 listener라고 적혀있다.
리스너는 특정 조건을 갖춘 객체 또는 콜백함수를 구현하는 객체라고 쓰여있다.
firefox에서는 listener자리에 객체를 받기도 하지만 보통 콜백함수로 생각하면 되겠다.
이벤트 리스터 콜백함수
listener의 콜백함수는 단일 매개변수 즉 하나의 매개변수를 받으며, 이 매개변수에는 '발생한 이벤트를 설명하는 Event에 기반한 객체' 즉 Event 인스턴스가 오며, 반환값이 없다고 한다.
여기서 this의 값은 '전달된 이벤트 Argument의 currentTarget 속성과 같다고 한다.
즉 this에는 currnetTarget이 바인딩 된다.
결국 addEventListener에는 매개변수가 event 객체로 지정이 되고, this에는 currentTarget이 바인딩된다.
위의 사진처럼 cbFunc.bind(obj)로 하면 cbFunc가 가리키는 this가 간단히 obj를 가리키게 된다.
그 이유는 bind함수는 함수가 가리키는 this만 바꾸고 호출은 하지 않는다. 콜백함수 이므로 addEventListener의 type인 click시에 bind가 작동됨을 알 수 있다.
마지막으로 정리를 하자면
위의 사진에서 obj.logValues(1, 2)를 호출하면 어떻게 될까?
logValues를 obj의 매소드로 호출했기 때문에 this는 obj를 가리킨다.
그러므로 결과값은 [1,2,3] 1 2를 가지게 된다.
그렇다면 arr.forEach(obj.logValues)를 호출하면 어떻게 될까?
이번에 obj.logValues는 콜백함수로서 호출이 되었다.
주의할 점은 forEach는 obj.logValues를 콜백함수로 전달은 받았지만 메서드로 호출한 것이 아니다.
그냥 obj.logValues가 가리키고 있는 '함수'만 똑 떼어서 전달을 한 것이다.
즉, logValues: function(v, i){ } 이 부분만 전달한 것이다.
그걸 받은 forEach역시 이걸 메서드가 아닌 함수로써 호출하게 된다.
그러니 이때는 this는 obj가 아닌 전역객체가 담기게 되는 것이다.
주의: 콜백으로 넘기는건 무조건 함수이다.
그렇다면 여기서 this를 obj로 가리키게 하려면 어떻게 할까?
간단히 함수뒤에 bind(obj)를 붙여 this를 바꾸어 주거나, forEach의 두번째 인자는 thisArg를 가리키므로 여기에 obj를 넣어주어 forEach의 특성을 이용해도 된다.
메소드로서 호출, 콜백함수로의 전달 구분이 가능해야 한다!