콜백 함수는 다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수이다.
let count = 0;
let cbFunc = function() {
console.log(count);
if (++count > 4) clearInterval(timer);
};
let timer = setInterval(cbFunc, 300);
// -- 실행 결과 --
// 0 (0.3초)
// 1 (0.6초)
// 2 (0.9초)
// 3 (1.2초)
// 4 (1.5초)
setInterval의 첫번째 인자로 cbFunc 콜백함수를 넘겨주니, setInterval이 cbFunc의 제어권을 넘겨 받는다.
콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수 호출 시점에 대해 제어권을 가진다.
let newArr = [10, 20, 30].map(function(currentValue, index) {
console.log(currentValue, index);
return currentValue + 5;
});
console.log(newArr);
// -- 실행 결과 --
// 10 0
// 20 1
// 30 2
// [15, 25, 35]
map 메서드는 첫번째 인자로 callback 함수를 받고, 생략 가능한 두 번째 인자로 콜백 함수 내부에서 this로 인식할 대상을 특정할 수 있다. 두 번째 인자(thisArg)를 생략할 경우 일반적인 함수와 마찬가지로 this에 전역객체가 바인딩 된다.
map 메서드를 호출해서 원하는 배열을 얻으려면 map 메서드에 정의된 규칙(콜백 함수의 인자로 넘어올 값들 및 그 순서)에 따라 함수를 작성해야한다.
콜백 함수의 제어권을 넘겨받은 코드는 콜백 함수를 홏출할 때 인자에 어떤 값들을 어떤 순서로 넘길지에 대한 제어권을 가진다.
"콜백 함수도 함수이기에 기본적으로는 this가 전역 객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다."
call/apply 메서드의 첫번째 인자로 콜백 함수 내부에서의 this가 될 대상을 명시적으로 바인딩한다.
setTimeout(function() {
console.log(this);
}, 300); // (1) Window { ... } - 별도의 인자로 this를 넘겨주지 않음
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this); // (2) Window { ... } - 별도의 인자로 this를 넘겨주지 않음
});
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener(
'click',
function(e) {
console.log(this, e); // (3) <button id="a">클릭</button>
} // MouseEvent { isTrusted: true, ... } - addEventListener의 this를 넘겨줌
);
콜백함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출한다.
let obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i); //
},
};
obj.logValues(1, 2); // { vals: [1, 2, 3], logValues: f } 1 2
[4, 5, 6].forEach(obj.logValues);
// console.log : Window { ... } 4 0
// console.log : Window { ... } 5 1
// console.log : Window { ... } 6 2
obj.logValues 메서드는 forEach의 콜백 함수로서 호출되었다. 따라서 별도로 this를 지정하는 인자를 지정하지 않았으므로 함수 내부에서 this는 전역객체를 바라본다.
bind 메서드를 이용하여 내부 함수에 this를 전달한다.
let obj1 = {
name: 'obj1',
func: function() {
console.log(this.name);
},
};
setTimeout(obj1.func.bind(obj1), 1000);
var obj2 = { name: 'obj2' };
setTimeout(obj1.func.bind(obj2), 1500);
동기적 코드 : 현재 실행 중인 코드가 완료된 후에야 다음 코드를 실행하는 방식
비동기적 코드 : 비동기적인 코드는 현재 실행 중인 코드의 완료 여부와 무관하게 즉시 다음 코드로 넘어간다.
비동기적인 코드를 동기적으로 작동하는 것처럼 보이게 하기 위해 Promise, async/await 도입