호출 시점에 대한 제어권
// setInterval: 반복해서 매개변수로 받은 콜백함수의 로직을 수행
let count = 0;
let cdFunc = function() {
console.log(count);
if(++count > 4) clearInterval(timer)
};
// setInterval의 콜백함수로 전달
let timer = setInterval(cbFunc, 300);
// 직접 호출
cbFunc();
마지막처럼 cbFunc()를 직접 호출하는 경우 함수의 호출 시점은 프로그래머가 제어할 수 있다. 하지만 setInterval의 콜백함수로 전달하는 경우, 300ms 간격으로 setInterval이 호출 시점을 제어하게 된다.
인자에 대한 제어권
let newArr = [10, 20, 30].map(function (currentValue, index) {
console.log(currentValue, index);
return currentValue + 5;
});
map과 같은 메서드를 사용하는 경우 정해진 규칙을 활용해야 한다. 내가 임의로 index를 첫번째 인자로 넘기고 싶다하더라도 제어할 수 없다. 따라서 인자에대한 제어권이 호출한 메서드 (map)에 있다는 것!
콜백함수의 this 바인딩
제어권을 넘겨받은 코드에서 콜백 함수에 별도로 this가 될 대상을 지정할 경우, 콜백함수 내부의 this는 그 대상을 참조한다!
Array.prototype.myMap = function(callback, thisArg) {
let mappedArr = [];
for(let i = 0; i < this.length; i++) { // this는 myMap을 호출한 배열
let mappedValue = callback.call(thisArg || global, this[i]);
mappedArr[i] = mappedValue;
}
return mappedArr;
};
let newArr = [1, 2, 3].myMap(function(number) {
return number * 2;
});
console.log(newArr); // [2, 4, 6]
객체의 메서드를 콜백함수로 전달한 경우 this
const obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
},
};
obj.logValues(1, 2); // obj 1 2
일반적으로 메서드를 호출하는 경우 호출한 주체(객체)가 this다.
const obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
if(this === global) {
console.log("this가 global입니다.");
} else {
console.log(this, v, i);
}
},
};
[4, 5, 6].forEach(obj.logValues); // this가 global입니다. (3번 출력)
forEach는 콜백함수에 요소의 값과 인덱스를 매개변수로 넘겨준다. 따라서 logValues의 매개변수로는 4, 0 / 5, 1 / 6, 2가 전달된다.
obj.logValues의 형태때문에 obj가 호출의 객체라고 생각하기 쉽지만 이는 obj.logValues의 값인 function(v, i) { }를 가져온 것일 뿐이다! (호출하지 않음) 따라서 obj.logValues는 함수로서 독립적으로 실행된 것이고 (특정 객체의 메서드로 호출된 것이 아님) global을 this로 갖게된다.
콜백함수 내부의 this에 다른 값 바인딩하기
const obj1 = {
name: "obj1",
func: function () {
console.log("this: ", this);
console.log("this.name: ", this.name);
},
};
setTimeout(obj1.func, 1000); // Timeout 객체, undefined
위와 같이 실행하는 경우 1초 후 obj1의 이름을 출력하지 않는다! obj1이 호출의 주체가 아니기 때문이다. 따라서 원하는 기능을 위해 bind()를 이용해 호출 전 this를 obj1로 바인딩해줄 수 있다. bind만 가능한 것은 아니다!
const obj1 = {
name: "obj1",
func: function () {
console.log("this: ", this);
console.log("this.name: ", this.name);
},
};
const boundObj1 = obj1.func.bind(obj1);
setTimeout(boundObj1, 1000); // obj1 객체, obj1
const obj2 = {
name: "obj2",
};
setTimeout(obj1.func.bind(obj2), 1000); // obj2 객체, obj2
'JavaScript' 카테고리의 다른 글
[JS] Generator 로그 순서 이해하기 (0) | 2024.07.24 |
---|---|
[JS] 콜백지옥 해결방안 (기명함수, promise, generator, async/await) (0) | 2024.07.24 |
[JavaScript] this (정의, 활용, 바인딩, call, apply, bind) (2) | 2024.07.23 |
[JavaScript] 실행 컨텍스트 및 콜스택 (0) | 2024.07.23 |
[JavaScript] 깊은 복사와 얕은 복사 (0) | 2024.07.23 |