콜백함수
다른 코드(함수 또는 메서드)에게 인자로 넘겨줌으로써 그 제어권도 함께 위임한 함수입니다. 콜백 함수를 위임받은 코드는 자체적인 내부 로직에 의해 이 콜백 함수를 적절한 시점에 실행할 것입니다.
콜백 함수 내부에서 this가 가리키는 대상
콜백 함수도 함수이기 때문에 기본적으로는 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 됩니다.
setTimeout(function () { console.log(this); }, 300) // Window { ... }
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this) // Window { ... }
})
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a')
.addEventListener('click', function (e) {
console.log(this, e); // <button id="a">클릭</button>, MouseEvent { ... }
}
);
콜백함수로 메서드를 전달하면 메서드로 호출될까?
콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로서 호출됩니다. 메서드로서 호출할 때가 아니고 별도로 this를 지정하는 인자를 지정하지 않을 경우 함수 내부에서의 this는 전역객체를 바라보게 됩니다.
var 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); // Window { ... } 4 0
// Window { ... } 5 1
// Window { ... } 6 2
콜백 함수 내부에서 this가 객체를 바라보게 하려면?
별도의 인자로 this를 받는 함수의 경우에는 여기에 원하는 값을 넘겨주면 되지만 그렇지 않은 경우에는 this의 제어권도 넘겨주게 되므로 사용자가 임의로 값을 바꿀 수 없습니다. 그래서 다음과 같은 방법을 사용합니다.
- this를 다른 변수에 담아 콜백 함수로 활용할 함수에서는 this 대신 그 변수를 사용하게 하고, 이를 클로저로 만드는 방식
var obj = {
name: 'obj1',
func: function () {
var self = this;
return function () {
console.log(self.name)
}
}
}
var callback = obj.func();
setTimeout(callback, 1000);
- bind 메서드를 이용하는 방법
var obj = {
name: 'obj1',
func: function () {
console.log(self.name)
}
}
setTimeout(obj.func.bind(obj), 1000);
var obj2 = { name: 'obj2' };
setTimeout(obj.func.bind(obj2), 1000);
콜백 지옥
콜백 함수를 익명 함수로 전달하는 과정이 반복되어 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상입니다. 주로 이벤트 처리나 서버 통신과 같이 비동기적인 작업을 수행하기 위해 이런 형태가 자주 등장하곤 하는데, 가독성이 떨어질뿐더러 코드를 수정하기도 어렵습니다.
콜백 지옥을 해결하는 방법
콜백 지옥을 해결하는 방법으로는 첫 째로 익명의 콜백함수를 모두 기명함수로 전환하는 방법이 있습니다. 둘 째로는 비동기 작업을 동기적으로 표현해줄 수 있는 Promise, Generator, async/await를 활용하는 방식이 있습니다.