TIL

TIL 240820 (콜백 함수 1)

j-coder 2024. 8. 20. 22:02

1. 콜백함수

콜백함수는 다른 코드의 인자로 전달되어 그 코드 내에서 호출되는 함수를 뜻한다.

기초문법에서 배운 setTimeout, foreach도 콜백함수이다.

 

예시)

// setTimeout

setTimeout(function() {

    console.log("Test");

  }, 1000);

 

  // forEach

  const numbers = [6, 7, 8, 9, 10];

 

  numbers.forEach(function(number) {

    console.log(number);

  });

 

1 - 1 제어권(호출 시점)

콜백함수는 호출 시점에 대한 제어권을 갖는다.

콜백  함수의 제어권을 받은 코드(setinterval) : 반복해서 매개변수로 받은 콜백함수의 로직을 수행

 

let count = 0;


// cbFunc라는 이름의 콜백 함수를 정의

let  TestFunc = function() {

    console.log(count);

   

    // count를 1 증가시키고, 6보다 크면 타이머를 중지

    if (++count > 5) clearInterval(timer);

}


// 300밀리초마다 cbFunc 함수를 실행하는 타이머를 설정

let  timer = setInterval(TestFunc , 500);

 

1 - 2 제어권(인자)

// index, currentValue : 사람이 이해할 수 있는 변수명(값)

let newArr = [1, 2, 3].map(function(currentValue, index){

    console.log(currentValue, index);

    return currentValue + 10;

});

 

console.log(newArr);

 

currentValue와 index 순서를 바꾸면 사람처럼 이해할 수 없어 의도하지 않은 값이 나온다.

 

1 - 3 제어권(this)

this는 전역 객체를 참조한다.

하지만 예외 사항이 있다. 제어권을 넘겨받을  코드에서 콜백 함수에 별도로 this 대상을 정한경우는

그 대상을 참조한다.

for (var i = 0; i < this.length; i++) {

    // call의 첫 번째 인자는 thisArg가 존재하는 경우는 그 객체, 없으면 전역객체

    // call의 두 번째 인자는 this가 배열일 것(호출의 주체가 배열)이므로,

    // i번째 요소를 넣어서 인자로 전달

 

    var mappedValue = callback.call(thisArg || global, this[i]);

    mappedArr[i] = mappedValue;  // callback 함수 결과

}

return mappedArr;

};

 

1 - 4 콜백 함수 도 함수다

콜백 함수로 객체의 메서드를 전달해도, 매서드가 아닌 함수로 호출 한다.

2가지 속성 (values, logvalue)

 

var obj = {

    vals: [7, 8, 9],

    logValues: function(v, i) {

        console.log(">>> test starts");

        if (this === global){

            console.log("this가 global입니다. 원하지 않는 결과") // this가 전역객체인 경우 경고 메시지

        }else{

            console.log(this, v, i); // this가 obj 객체인 경우 this와 인자 v, i 출력

        }

        console.log(">>> test ends");

    }

};


//method로써 호출

obj.logValues(3, 4);


// callback => obj를 this로 하는 메서드를 그대로 전달한게 아니에요

// 단지, obj.logValues가 가리키는 함수만 전달한거에요(obj 객체와는 연관이 없습니다)


// foreach, map, filter

[4, 5, 6].forEach(obj.logValues); // this는 전역객체가 되어서 "this가 global입니다. 원하지 않는 결과" 출력

 

1 - 5 this에 다른 값 바인딩

1 - 5 - 1 전통적 방식(closure)

현재 함수가 끝나도 영향을 미친다.

 

(1) 강제로 this 를 제어하는 방식

var obj1 = {

    name: 'obj1',

    func: function() {

        var self = this; //이 부분!

        return function () {

            console.log(self.name);

        };
    }
};

// 단순히 함수만 전달한 것이기 때문에, obj1 객체와는 상관이 없다.

// 메서드가 아닌 함수로서 호출한 것과 동일

var callback = obj1.func();

setTimeout(callback, 1000);

 

(2) 첫 번째 예시를 재활용한 방식

 

var obj1 = {

    name: 'obj1',

    func: function() {

        var self = this; //이 부분!

        return function () {

            console.log(self.name);

        };

    }

};

----------------------------------------------------------------------

// 위의 obj1의   func를 직접 obj2와 obj3에 대입해보면 더 보기 쉽다

 

var obj2 = {

    name: 'obj2',

    func: obj1.func

};

var callback2 = obj2.func();

setTimeout(callback2, 1500);

 

var obj3 = { name: 'obj3' };

var callback3 = obj1.func.call(obj3);

setTimeout(callback3, 2000);

 

(3) bind 메서드 활용 (1), (2)번보다 좋은 방법

// this를 바인딩해서 새로운 함수를 리턴


var obj1 = {

    name: "obj1",

    func: function () {

        console.log(this.name);

    },

};


setTimeout(obj1.func.bind(obj1), 1000);       // 이것이

// var boundObj1 = obj1.func.bind(obj1);

// setTimeout(boundObj1, 1000);             //  이 두줄로 바꿀수있음


var obj2 = { name: 'obj2' };

//함수 자체를 obj2에 바인딩

//obj1.func를 실행할 때 무조건 this는 obj2로 고정해줘!

// 어떤 this든 원하는대로 바인드할수있다는걸 보여주는  코드

setTimeout(obj1.func.bind(obj2), 1500);