코어 자바스크립트 - 콜백함수
콜백함수는 함수를 처리해달라고 다른 곳에 넘겨 제어권을 위임합니다. 그리고 나서 처리된 값을 다시 받습니다.
앞서 보았던 this에서 이벤트 핸들러가 좋은 예시가 되겠습니다.
콜백함수가 넘겨주는 제어권은 실행 시점, 매개변수, this가 있습니다.
▶ 실행 시점
//setInterval 일정 시간 간격으로 함수 호출
setInterval(function () {
console.log('1초마다 실행');
}, 1000);
위의 경우 함수의 실행 시점을 setInterval에게 넘겨주었음으로 함수는 콜백함수이다.
▶ 매개변수
var arr = [1, 2, 3, 4, 5];
var entriees = [];
arr.forEach(function(v,i) { // v: value , i: index
entries.push([i, v, this[i]]);
}, [10, 20, 30, 40, 50]);
console.log(entries);
//[[0,1,10], [1,2,20], [2,3,30], [3,4,40], [4,5,50]]
여기서 우리가 궁금한 점은 this로 어떻게 10, 20, 30, 40, 50 값이 나왔는지입니다. 이를 알기 위해서는 forEach에 어떤 규칙이 있는지 살펴보아야 합니다.
arr.forEach(callback(currentvalue[, index[, array]])[, thisArg])
currentValue: 배열에서 현재 처리 중인 요소
index: 배열에서 현재 처리 중인 요소의 인덱스
array: forEach()가 적용되고 있는 배열
thisArg: 선택사항. callback을 실행할 때 this로서 사용하는 값.
forEach를 사용하면 callback함수를 적고 이후 thisArg를 추가할 수 있게 해주었습니다. 위 코드에서 [10, 20, 30, 40, 50]이 바로 thisArg가 되는 것입니다.
이처럼 forEach에서 정의된 규칙이 있다면 따를 수 밖에 없으며 forEach를 사용할 함수를 만들거면 이에 맞게 만들어야 합니다.
▶ this
document.body.innerHTMl = '<div id = "a">abc</div>';
function cbFunc(x) {
console.log(this,x);
}
document.getElementById('a').addEventListener('click', cbFunc);
//<div id="a">abc</div>
//PointerEvent {isTrusted: true, ~~~~~}
addEventListener가 콜백함수를 받을 때 this는 eventTarget으로 하고 콜백함수의 첫번째 인자에는 event 객체를 넘겨주도록 정해놓았기 때문입니다.
target.addEventListener(type, listener[, options]);
target.addEventListener(type, listener[, useCapture]);
addEventListener(type, callback, options)
type: click, mousemove, keyup, scroll 등 반응할 이벤트 유형을 나타내는 문자열
listener: 특정 조건을 갖춘 객체, 콜백함수
options: 옵션을 담은 객체 등이 온다.
addEventListener에는 매개변수가 event 객체로 지정이 되고 this에는 currentTarget이 바인딩 된다.
document.body.innerHTMl = '<div id = "a">abc</div>';
function cbFunc(x) {
console.log(this,x);
}
const obj = {a:1};
document.getElementById('a').addEventListener('click', cbFunc.bind(obj));
this가 obj로 바뀌게 하려면 bind.(obj)를 걸어주면 됩니다.
전체 내용을 정리하여 콜백함수의 특징을 정리해보겠습니다.
- 다른 함수(A)의 인자로 콜백함수(B)를 전달하면, A가 B의 제어권을 갖게 된다.
- 특별한 요청(bind)가 없는 한 A가 미리 정해놓은 방식에 따라 B를 호출합니다.
- 미리 정해놓은 방식이란 어떤 시점에 콜백을 호출할지, 인자에는 어떤 값들을 지정할지, this에 무엇을 바인딩할지 등이다.
마무리하기 전, 코드 하나만 더 보겠습니다.
var arr = [1, 2, 3, 4, 5];
var obj = {
vals: [1,2,3],
logValues: function(v, i) {
if(this.vals) {
console.log(this.vals, v, i);
} else {
console.log(this, v, i);
}
}
};
obj.logValues(1,2); // 메소드로 호출 [1,2,3] 1 2
arr.forEach(obj.logValues); // 콜백함수로 전달 Window{...} 1 0 , Window{...} 2 1 ...
//this로 obj를 지정하고 싶다면? bind, thisArg
arr.forEach(obj.logValues.bind(obj));
arr.forEach(obj.logValues, obj);
이것을 보며 '메소드로 호출'과 '콜백함수로 전달'을 구분할 수 있어야 합니다.