1. 콜백 함수: 다른 코드의 인자로 넘겨주는 함수
-콜백 함수를 넘겨받은 코드는 콜백 함수를 필요에 따라 적절한 시점에 실행할 것
-특정 코드에 콜백 함수에 대한 제어권을 넘겨주는 것
2. 제어권
1) 호출 시점에 대한 제어권
-예시
var count = 0;
var timer = setInterval(function () {
console.log(count);
if(++count>4) clearInterval(timer);
},300);
// 결과
// 0 (0.3초)
// 1 (0.6초)
// 2 (0.9초)
// 3 (1.2초)
// 4 (1.5초)
-setInterval 함수의 기본 인자는 함수와 delay로, delay 값마다 함수를 실행
-clearInterval은 setInterval함수를 즉시 종료하도 싶을 때 사용, 인자는 setInterval함수가 리턴해주는 값으로 사용(예시에서는 timer)
-즉, 예시는 300ms마다 console에 count를 출력하고,
1을 더한 후 4와 비교,
4보다 크지 않으면 반복실행,
4보다 크면 즉시 종료
-설명을 위한 예시 정리
var count = 0;
var cbFunc = function() {
console.log(count);
if(++count>4) clearInterval(timer);
};
var timer = setInterval(cbFunc, 300);
-cbFunc에 대한 제어권은 원래 사용자에게 있음
→cbFunc를 정의한 뒤 사용하려면, 코드를 "cbFunc() "와 같이 입력하여 직접 호출해야 함
→이렇게 하면 count에 1씩 더해진 값이 정해져 실행 횟수에 따라 count가 1씩 증가하여 출력되는 것은 똑같지만,
4와 비교되는 것이 출력 이후라 4보다 크다고 출력이 안되는 것은 아님
→또한, 매번 코드를 입력하여 호출해야함
-setInterval 함수의 인자로 cbFunc()함수를 넘겨주며 cbFunc()함수의 제어권을 setInterval 함수로 넘김
→setInterval 함수가 스스로 판단하여, 두번째 인자로 받은 숫자만큼의 시간마다 자동으로 cbFunc()함수를 실행
→매번 count를 4와 비교하는 동작도 실행하다가 4보다 커지면 setInterval 함수 자체를 중지하며 4 이후의 숫자의 출력은 중지됨
-콜백 함수의 제어권을 넘겨받은 코드(setInterval)는 콜백 함수 호출 시점(cbFunc 실행, count를 console에 출력)에 대한 제어권을 가짐
2) 인자에 대한 제어권
-예시
var newArr = [10, 20, 30].map(function (currentValue, index) {
console.log(currentValue, index);
return currentValue + 5;
});
console.log(newArr);
// 결과
// 10 0
// 20 1
// 30 2
// [15, 25, 35]
-map메서드는 메서드 대상이 되는 배열(예시에서 [10, 20 ,30])의 모든 요소들을 처음부터 끝까지 하나씩 콜백 함수에 적용,
콜백 함수의 실행 결과를 모아 새로운 배열 생성
-즉, 예시에서 10, 20, 30 각각의 값과 인덱스를 하나씩 출력하고,
새로운 배열에 저장하기 전 값에 5씩 더하여 새로운 배열([15, 25, 35]) 생성하여 출력
-예시 2
var newArr = [10, 20, 30].map(function (index, currentValue) {
console.log(index, currentValue);
return currentValue + 5;
});
console.log(newArr);
// 결과
// 10 0
// 20 1
// 30 2
// [5, 6, 7]
-콜백 함수의 인자 index와 currentValue의 위치를 바꿈
→map 메서드의 콜백 함수는 기본적으로 (요소, 인덱스, [, 배열], [, thisArg])의 순서로 인자를 받도록 되어 있음
→즉, map 메서드 내의 콜백 함수에서 (index, currentValue)로 (인덱스, 요소)의 순서로 이름을 붙였다고 해도 이름만 붙인 것일 뿐
실제로, 컴퓨터에서는 index라고 이름 붙은 요소, currentValue라고 이름 붙은 인덱스라고 인식함
→따라서, index, currentValue 순서로 출력을 명령하면 (index가 아닌 요소, currentValue가 아닌 인덱스)의 순서로 출력됨
→또한, +5가 더해지는 주체도 currnetValue의 이름이 붙은 인덱스이므로 0, 1, 2에 각각 5씩 더해져 새로운 배열에 저장됨
-콜백 함수의 제어권을 넘겨받은 코드(map)은 콜백 함수 인자의 순서(요소, 인덱스)에 대한 제어권을 가짐
3) this에 대한 제어권
-콜백 함수도 함수이기 때문에 별도로 this를 지정하지 않으면 this에는 기본적으로 전역객체가 설정됨
-예시
Array.prototype.map = function(callback, thisArg) {
var mappedArr = [];
for (var i = 0; i < this.length ; i++) {
var mappedValue = callback.call(thisArg || window, this[i], i, this);
mappedArr[i] = mappedValue;
}
return mappedArr;
};
-callback 함수의 제어권을 넘겨받는 코드(function())에서 this 객체를 thisArg에서 지정해준다면, 콜백 함수를 call할 때, 콜백 함수의 this를 function()에서 넘겨준 thisArg를 지정하고, 넘겨주지 않으면 기본적으로 설정된대로 전역객체를 지정함
3. 콜백 함수는 함수다
-콜백 함수로 어떤 객체의 메서드를 전달하더라도 그 메서드는 메서드가 아닌 함수로 호출됨
-예시
var obj = {
vals: [1, 2, 3],
logValues: function(v, i) {
console.log(this, v, i);
}
};
obj.logValues(1, 2);
[4, 5, 6].forEach(obj.logValues);
-obj.logValues(1, 2): obj 객체의 logValues 메서드로서 정의되어 this는 obj 객체를 가리키고 1과 2는 각각 function의 인자 v와 i로 할당되어 출력됨
-[4, 5, 6].forEach(obj.logValues): obj,logValues를 forEach의 콜백 함수로 사용하여, obj 객체의 logValues 메서드가 아닌 obj.logValues가 담고 있는 함수 function만 전달됨
→obj 객체와의 직접적인 연관이 없어지고 forEach에서 별도의 this 객체를 지정하지 않아 this는 전역객체를 가리키게 됨
→객체의 메서드를 전달하더라도 콜백 함수로서 전달하면 메서드가 아닌 함수로 전달됨
4. 콜백 함수 내부의 this에 다른 값 바인딩
-위에서 봤듯이, 원래 객체의 메서드를 콜백 함수로 전달하면 해당 객체를 this로 설정할 수 없음
-이때, 콜백 함수 내부에서 메서드의 객체를 this로 설정하는 방법
-전통적인 방법: 메서드 내에서 임의의 변수(self 등)에 this를 담아 메서드를 담은 객체를 this로 설정
var obj1 = {
name: 'obj1',
func: function() {
var self = this;
return function() {
console.log(self.name);
};
}
};
var callback = obj1.func();
setTimeout(callback, 1000);
-setTimeout 함수의 콜백 함수로 obj1 객체의 func 메서드를 주어 함수로 변경되어 this가 전역 객체를 가리켜야 하지만, 메서드 내에서 self에 this를 할당했으므로 self.name은 obj1 객체의 name을 가리키게 됨
-따라서, 1000ms(1초) 뒤에 'obj1'이 출력됨
// self라는 임의의 변수 생성없이 하드코딩하는 방법도 있지만, this를 이용한 재활용을 할 수 없게 됨
var obj1 = {
name: 'obj1',
func: function() {
console.log(obj1.name);
}
};
setTimeout(obj1.func, 1000);
-var self = this로 지정한 것을 재활용하는 예시
var obj1 = {
name: 'obj1',
func: function() {
var self = this;
return function() {
console.log(self.name);
};
}
};
// obj1의 func를 복사한 것을 obj2내의 func로 사용
var obj2 = {
name: 'obj2',
func: obj1.func
};
var callback2 = obj2.func();
setTimeout(callback2, 1500);
// obj3은 name만 지정한 후, call을 사용하여 obj1의 func를 obj3에 적용
var obj3 = { name: 'obj3' };
var callback3 = obj1.func.call(obj3);
setTimeout(callback3, 2000);
→obj1 객체 내에서 func 메서드의 this를 self로 지정해놨으므로 obj2, obj3에 복사되어 이용될 때, self에는 obj1의 func를 호출할 때의 각 객체, obj2와 obj3이 각각 할당됨
→따라서, self.name에는 obj2.name, obj3.name이 설정되어 1.5초, 2초 뒤에 'obj2', 'obj3'이 각각 출력됨
-this.name을 obj1.name으로 설정하면 obj1 객체의 func를 콜백 함수로 사용할 때는 obj1 객체를 콜백함수의 this로 지정할 수 있지만, obj2, obj3 등에서 func를 콜백함수로써 재활용하지 못함
-하지만, this를 self 등의 변수에 넣어두면, 메서드를 호출하는 객체가 바뀔 때마다 메서드의 this를 해당 객체로 바꿔서 지정해줄 수 있으므로 재활용이 가능해짐
-전통적인 방법 외에 bind를 사용하는 방법
var obj1 = {
name: 'obj1',
func: function() {
console.log(this.name);
}
};
setTimeout(obj1.func.bind(obj1), 1000);
// obj1 객체의 func 메서드를 obj2에 bind하여 사용
var obj2 = { name: 'obj2'};
setTimeout(obj1.func.bind(obj2), 1500);
→setTimeout(obj1.func.bind(obj1), 1000): obj1 객체의 func 메서드가 콜백함수로 쓰여 함수의 형태가 되고, this 객체를 주지 않았으면 전역객체가 this로 할당되었겠지만, bind를 통해 obj1 객체를 bind해주어 this에 obj1객체가 할당됨.
→따라서, obj1의 name, 'obj1'이 출력됨
→setTimeout(obj1.func.bind(obj2), 1500): obj1 객체의 func 메서드에 obj2 객체를 bind하여 사용하여, this에 obj2 객체가 할당됨
→따라서, obj2의 name, 'obj2'가 출력됨
'Front-end > Javascript' 카테고리의 다른 글
[코어 자바스크립트] 05. 클로저(1) (0) | 2022.12.20 |
---|---|
[코어 자바스크립트] 04. 콜백 함수(2) (0) | 2022.12.14 |
[코어 자바스크립트] 03. this(2) (0) | 2022.12.08 |
[코어 자바스크립트] 03. this(1) (0) | 2022.12.05 |
화면 오픈소스 사이트, codepen (0) | 2022.12.05 |