매개변수로 함수 객체를 전달해서 호출 함수 내에세 매개변수 함수를 실행하는 것을 말합니다.
즉, 파라미터로 일반적인 변수나 값을 전달하는 것이 아닌 함수 자체를 전달하는 것을 말합니다.
function sayHello(name, callback) {
const words = '안녕하세요 내 이름은 ' + name + ' 입니다.';
callback(words);
}
// 1️⃣
sayHello("인파", function (name) {
console.log(name);
});
1️⃣ 익명 함수
매개변수에 함수를 전달해 일회용으로 사용합니다.
그 때문에 함수의 이름을 명시할 필요가 없어 익명 함수 형태로 넣어주게 됩니다.
function sayHello(callback) {
var name = "Alice";
callback(name); // 2️⃣
}
// 1️⃣
sayHello((name) => {
console.log("Hello, " + name);
});
1️⃣ 익명 화살표 콜백 함수
더 간결성을 얻기 위해 javascript의 화살표 함수를 사용합니다.
2️⃣ 콜백 함수 호출
function introduce (lastName, firstName, callback) {
var fullName = lastName + firstName;
callback(fullName); // 1️⃣
}
function say_hello (name) {
console.log("안녕하세요 제 이름은 " + name + "입니다");
}
function say_bye (name) {
console.log("지금까지 " + name + "이었습니다. 안녕히계세요");
}
// 2️⃣
introduce("홍", "길동", say_hello);
introduce("홍", "길동", say_bye);
1️⃣ 콜백 함수 호출
2️⃣ 콜백 함수의 이름만 인자로 전달
javascript는 null과 undefined 타입을 제외하고 모든 것을 객체로 다룹니다.
그래서 매개변수에 일반적인 변수나 상수뿐만 아니라 함수 자체를 객체로서 전달이 가능합니다.
여러 호출에 재활용해 자주 이용되는 경우, 별도로 함수를 정의하고 함수의 이름만 호출 함수의 인자에 전달하는 식으로 사용이 가능합니다.
이 특징을 응용하면, 매개변수에 전달할 콜백 함수 종류만을 바꿔줌으로서 여러가지 함수 형태를 다양하게 전달이 가능합니다.
let button = document.getElementById("button");
// 1️⃣
button.addEventListener("click", function () {
console.log("Button clicked!");
});
1️⃣ callback 함수
addEventListener는 특정 이벤트가 발생했을 때 콜백 함수를 실행하는 method입니다.
클릭과 같은 이벤트를 처리하기 위해 등록하는 이벤트 리스너로 콜백함수를 활용합니다.
let numbers = [1, 2, 3, 4, 5];
let doubled = [];
// 1️⃣
numbers.forEach(function (num) { // 2️⃣
doubled.push(num * 2);
});
console.log(doubled);
1️⃣ forEach method
numbers 배열의 각 요소를 도는 반복문을 생성합니다.
2️⃣ callback 함수
각 요소에 callback 함수 실행합니다.
let userData = {
signUp: '2021-4-06 12:00:00',
name: 'Not Set',
setName: function(firstName, lastName) {
this.name = firstName + ' ' + lastName;
}
}
function getUserName(firstName, lastName, callback) {
callback(firstName, lastName);
}
getUserName('홍', '길동', userData.setName);
// 1️⃣
console.log('1: ', userData.name);
console.log('2: ', window.name);
1️⃣ 1: Not Set, 2: 홍 길동
콜백 함수는 다른 함수의 인자로 전달되는 함수입니다.
콜백 함수는 자신을 전달받은 함수에 의해 호출됩니다.
이때, 콜백 함수 내부에서의 this는 해당 콜백 함수의 제어권을 넘겨받은 함수가 정의한 바에 따릅니다.
만약 정의하지 않은 경우에는 전역 객체를 참조하게 됩니다.
따라서, userData 객체의 setName 프로퍼티 함수 내부에서 사용된 this.name이 전역 객체 window의 name을 가리킵니다.
call() : 첫 번째 인자로 this 객체를 사용하고, 나머지 인자들은 ,로 구분합니다.
let userData = {
signUp: '2021-4-06 12:00:00',
name: 'Not Set',
setName: function(firstName, lastName) {
this.name = firstName + ' ' + lastName;
}
}
function getUserName(firstName, lastName, callback, data) { // 1️⃣
// 2️⃣
callback.call(data, firstName, lastName);
getUserName('홍', '길동', userData.setName, userData);
console.log('1: ', userData.name); // 홍 길동
console.log('2: ', window.name); // Not Set
1️⃣ userData를 받는 매개변수 data를 추가합니다.
2️⃣ call method
첫 번째 인자인 data를 this로 사용합니다.
apply() : 첫 번째 인자로 this 객체를 사용하고, 나머지 인자들은 배열 형태로 전달합니다.
let userData = {
signUp: '2021-4-06 12:00:00',
name: 'Not Set',
setName: function(firstName, lastName) {
this.name = firstName + ' ' + lastName;
}
}
function getUserName(firstName, lastName, callback, data) {
// 1️⃣
callback.apply(data, [firstName, lastName]);
}
getUserName('홍', '길동', userData.setName, userData);
console.log('1: ', userData.name); // 홍 길동
console.log('2: ', window.name); // Not Set
1️⃣ apply method
첫번째 인자인 data를 this로 사용하고, 사용할 파라미터들은 배열로 전달합니다.
화살표 함수는 자신만의 this를 가지지 않고 상위 스코프의 this를 참조합니다.
따라서, 전역 객체를 무시하고 자신을 들고 있는 상위 객체를 가리킵니다.
let userData = {
signUp: '2021-4-06 12:00:00',
name: 'Not Set',
// 1️⃣
setName: (firstName, lastName) => {
this.name = firstName + ' ' + lastName;
}
}
function getUserName(firstName, lastName, callback) {
// 2️⃣
callback(firstName, lastName);
}
getUserName('홍', '길동', userData.setName);
console.log('1: ', userData.name); // 홍 길동
console.log('2: ', window.name); // Not Set
1️⃣ 화살표 함수 사용
상위 객체인 userData를 this로 사용합니다.
2️⃣ call method 없이 callback 함수를 호출합니다.
콜백 함수를 사용하면 코드가 복잡하고 가독성이 떨어지는 문제가 있습니다.
특히, 여러 개의 비동기 작업을 순차적으로 수행해야 할 때는 콜백 함수가 중첩되어 코드의 깊이가 깊어지는 현상이 발생합니다.
이런 현상은 Callback Hell이라고 부릅니다.
// 1️⃣
function increaseAndPrint(n, callback) {
setTimeout(() => {
const increased = n + 1;
console.log(increased);
if (callback) {
// 2️⃣
callback(increased);
}
}, 1000);
}
increaseAndPrint(0, n => {
increaseAndPrint(n, n => {
increaseAndPrint(n, n => {
increaseAndPrint(n, n => {
increaseAndPrint(n, n => {
console.log('끝!');
});
});
});
});
});
1️⃣ increaseAndPrint
숫자 n을 파라미터로 받아와서 다섯번에 걸쳐 1초마다 1씩 더해 출력하는 함수입니다.
2️⃣ callback 함수 호출
이러한 콜백 함수의 코드 형태는 콜백 함수가 중첩되면서 들여쓰기 수준이 깊어져 코드의 가독성을 떨어뜨리며 코트의 흐름을 파악하기 어려워집니다.
또한, 콜백 함수마다 에러 처리를 따로 해줘야하고, 에러가 발생한 위치를 추적하기 힘듭니다.
참고
📚 콜백 함수(Callback) 개념 & 응용 - 완벽 정리
🌐 자바스크립트의 핵심 '비동기' 완벽 이해 ❗
📚 자바스크립트 Promise 개념 & 문법 정복하기