본문 바로가기
개발 공부 일지/코어 자바스크립트 (정재남)

[코어 자바스크립트] 콜백 함수

by yelimu 2025. 2. 25.

콜백함수 : 다른 코드의 인자로 넘겨주는 함수 

시계를 예시로 들면, 약속 시간이 8시일때 

1) 계속해서 8시가 되었는지 (내가) 시간을 확인한다. 

2) 8시에 알람을 맞춘다 → 8시가 되면 (시계가) 알람을 울려준다. : 즉 알람을 울리는 제어권이 시계에게 있음

 

이처럼 콜백함수를 다른 코드에 인자로 넘겨주면, 제어권도 함께 위임하게 된다.

콜백함수를 위임받은 코드는 자체적인 내부 로직에 의해 콜백함수를 적절한 때에 실행한다. 

var count = 0;
var cbFunc = function(){
    console.log(count);
    if(++ count > 4 ) clearInterval(timer);
}
var timer = setInterval(cbFunc, 300); // 제어권이 setInterval함수에 있음

cbFunc(); // 제어권이 사용자에게 있음

0.3초 마다 setInterval 의 인자로 전달받은 콜백함수인 cbFunc 를 실행함

var intervalID = scope.setInterval(func, delay[, param1, param2, ...])
· scope : 일반적인 브라우저에서는 Window 객체 -> window 생략 가능 (또는 Worker의 인스턴스) 
· delay [ms] 마다 func를 반복 실행한다. 매 실행마다 고유한 ID를 반환한다. 
· param1,2, ... 는 func의 인자로 전달된다. 
· clearInterval 로 반복 실행 종료

this

콜백함수를 호출하면 this는? 함수로서 호출한 것이므로 전역 객체가 바인딩된다.

함수, 메서드 내부에서 지정한 방식대로 this 바인딩이 일어난다.

 setTimeout(function (){ console.log(this)}, 300); // Window

[1,2,3,4,5].map(function(x){
    console.log(this) // Window
});

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector("#id").addEventListener('click', function(e){
    console.log(this) // <button id="a">클릭</button>
})
  • setTimeout 내부에서 콜백함수 호출 시 call 메서드의 첫번째 인자에 전역객체를 넘긴다 
  • map 메서드의 두번째 인자로 thisArg를 지정하지 않았기때문에 Window 바인딩
  • addEventListener : call 메서드 첫번째 인자에 addEventListener 의 this를 그대로 넘기도록 정의되어있기 때문에 호출 주체인 HTML 엘리먼트를 가리킨다. 
Array.prototype.map 구현하기 -> 어떻게 this 바인딩이 일어나는지 동작원리 확인
Array.prototype.mapFunc = function (callback, thisArg){
    var mappedArr = [];
    for (var i = 0; i < this.length; i++){ // 여기서 this 는 map메서드를 호출한 주체
        var mappedValue = callback.call(thisArg || window, this[i], i, this); // callback에 this 바인딩하고 나머지는 인자로 전달
        mappedArr[i] = mappedValue;
    }
    return mappedArr;
}​


객체의 메서드를 콜백함수로 호출하면 this는? = 마찬가지로 함수로 호출하니 전역객체 바인딩

var obj = {
    vals : [1,2,3],  
    logValues : function (v, i){
        console.log(this, v, i)
    }
}
obj.logValues(1,2);
//{vals: Array(3), logValues: ƒ} 1 2
 
[4,5,6].forEach(obj.logValues);
//Window {window: Window, self: Window, document: document, name: '', location: Location, …} 4 0
//Window {window: Window, self: Window, document: document, name: '', location: Location, …} 5 1
//Window {window: Window, self: Window, document: document, name: '', location: Location, …} 6 2

forEach의 콜백함수로

obj를 this로 하는 메서드를 전달한게 아니라, obj.logValues가 가리키는 함수만 전달한 것이다.

별도의 this 를 지정하는 인자를 전달하지 않았으므로 this 는 전역객체 바인딩

어떤 객체의 메서드를 콜백함수로 전달해도, 객체가 this에 바인딩 되지 않는다. 


어떤 객체의 메서드를 콜백함수로 전달할때, 그 객체를 this에 바인딩 시키는 방법은?

[전통적인 방법] : 변수에 this 를 할당해 전달하기

var obj1  = {
    name: "obj1",
    func : function (){
        var self = this;
        return function (){
            console.log(self.name);
        }
    }
}

var callback = obj1.func();
setTimeout(callback, 1000);

 

var obj2 = {
    name : "obj2", 
    func : function (){
        console.log(obj2.name);
    }
}
setTimeout(obj2.func, 1000);

단순히 obj2 객체의 name을 리턴하는 거라면 단순하지만, 이 경우 함수의 재사용이 불가능하다.

 

어떤 재사용이요?  obj1의 func 메서드를 재사용 해보자

var obj3 = {
    name: "obj3", 
    func : obj1.func
}
var callback3 = obj3.func(); 
// obj1.func를 복사한 obj3.func 를 할당 -> 호출한 객체 obj3가 this 바인딩 
setTimeout(callback3, 1500);

var obj4 = {
    name : "obj4"
}
var callback4 = obj1.func.call(obj4); 
//obj1.func를 실행하면서 this에 obj4를 명시적으로 바인딩
setTimeout(callback4, 2000)

반면 obj2.func는 obj2만 바라보도록 명시하여 다른 객체를 바라보게 할 수 없음

 

[ES5] : bind 메서드 사용

var obj1 = {
    name: "obj1",
    func: function (){
        console.log(this.name);
    }
}
setTimeout(obj1.func.bind(obj1), 1000); //  obj1
setTimeout(obj1.func, 1000); //  Window 


var obj2 = {name : "obj2"};
setTimeout(obj1.func.bind(obj2), 2000) // obj2

이 포스팅은 <코어 자바스크립트> 를 읽고 내용을 정리한 포스팅입니다. 틀린 내용이 있다면 알려주세요 _ _