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'가 출력됨

+ Recent posts