콜백함수 : 다른 코드의 인자로 넘겨주는 함수
시계를 예시로 들면, 약속 시간이 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
'개발 공부 일지 > 코어 자바스크립트 (정재남)' 카테고리의 다른 글
[코어 자바스크립트] 클로저 개념 (0) | 2025.03.04 |
---|---|
[코어 자바스크립트] 비동기 제어로 콜백 지옥 탈출하기 (1) | 2025.02.25 |
[코어 자바스크립트] this - 명시적 바인딩 (0) | 2025.02.21 |
[코어 자바스크립트] this - 규칙 (0) | 2025.02.21 |
[코어 자바스크립트] 데이터 타입 (기본형, 참조형) (0) | 2025.02.18 |