front-end/JavaScript

[JavaScript] 콜백함수, 화살표 함수

Ash_O 2023. 4. 20. 00:09

 

콜백함수

일반 함수에서 생길수 있는 문제점

function repeat(n){
   for (let i = 0; i<n ; i++) console.log(i);
}
repeat(5)

위 함수는 console.log(i)를 반복하며 호출한다.

해당 함수가 console.log(i)에 의존을 많이 한다. 

즉, repeat 함수는 console.log(i) 를 반복하는 작업만 수행하고 다른 작업을 수행하려면 다른 함수를 새로 정의해야 한다.

 

function repeat2(n){
   for (let i = 0; i < n; i++){
       if (i%2) console.log(i);
   }
}

위 함수는 반복하는 일은 공통적으로 수행하지만, 반복하면서 수행하는 일의 내용은 다르다.

함수의 일부분이 다르다는 이유로 매번 함수를 새롭게 정의해야 한다.

 

위 문제점은 아래와 같이 함수를 합성하여 해결할 수 있다

→ 함수의 변하지 않는 공통 로직은 미리 정의를 해두고, 경우에 따라 변경되는 로직을 함수로 추상화해서 전달하기

 

function repeat(n, f){
   for (let i=0; i<n; i++){
       f(i)
    }
}

let printAll = function(i) {
   console.log(i)
}

let printOdds = function(i) {
   if (i%2){
       console.log(i)
    }
}

repeat(5,printAll)
repeat(5,printOdds)

repeat 함수는 경우에 따라 변경되는 일을 함수 f로 추상화했고 매개변수로서 전달받는다

이렇게 됨으로 내부 로직이 자유로워져서 로직 일부분을 함수로 전달받아 수행하게 된다

 

이렇게 함수 내부로 전달되는 함수를 콜백함수라 한다.

 

콜백 함수 : 매개변수를 통해 다른 함수의 내부로 전달되는 함수

 

콜백함수를 전달받는 함수는 콜백 함수의 호출 시점을 결정해서 호출한다.

함수를 전달할땐 함수 자체를 전달해야 한다.

 

콜백 함수가 다른 함수 내부에서만 호출되면 콜백 함수를 익명 함수 리터럴이나 화살표 함수로 정의하는 것이 일반적이다.

function repeat(n, f){
    for (let i=0; i<n; i++){
        f(i)
    }
}

repeat(5, function(i){
    if(i%2) console.log(i);
})

repeat(5, (i) => {
    if(i%2) console.log(i);
})

 

이렇게 되면, 콜백 함수는 전달받은 함수가 호출될 때마다 평가되어 함수를 생성한다

콜백 함수를 다른 곳에서 호출할 필요가 있거나, 콜백 함수를 전달받는 함수가 자주 호출된다면
함수 외부에서 콜백 함수를 정의하고
전달하는 것이 효율적이다.

 

let printOdds = function(i) {
   if (i%2){
       console.log(i)
    }
}

function repeat(n, f){
   for (let i=0; i<n; i++){
       f(i)
    }
}

repeat(5,printOdds)

위와 같이 만들어 놓는다면 콜백 함수가 한번만 생성된다.

 

화살표 함수

화살표 함수는 function 키워드 대신 => 를 사용해 더 간략한 방법으로 함수를 만든다

화살표 함수는 항상 익명 함수로 정의한다.

const add = (x,y) => x+y;

몇 가지 제한점이 있다.

  • this나 super에 대한 바인딩이 없고, method로 사용될 수 없다.
  • new.target 키워드가 없다.
  • 스코프를 지정할 때 사용하는 call, apply, bind 를 이용할 수 없다
  • 생성자함수로 이용할 수 없다
  • yield를 화살표 함수 내부에서 사용할 수 없다

 

화살표 함수외의 다른 함수의 경우, 함수가 어떻게 호출되는지에 따라 this 값이 정해졌다.

생성자 함수로 호출되면 새로운 객체,

함수가 객체의 메서드로 호출되면 문맥상의 객체

 

코드 출처 : mdn

 

그래서 위와 같은 문제가 생긴다.

위 예제의 경우 var 키워드로 age를 내가 선언을 해뒀지만,

선언을 안했다면 window객체에 age 프로퍼티가 생성되고, 증가연산자가 실행되어 NaN이 window.age의 값이 된다

 

setInterval의 콜백으로 사용되는 growUp 함수가 Person의 인스턴스의 메서드가 아니기 때문에
growUp 함수 내부의 this는 전역을 가리키고 있어서 때문에 생기는 문제다

 

그래서 이전에는 this를 폐쇄될 수 있는 변수에 할당하여 해결할 수 있었다.

 

코드 출처 : mdn

 

이렇게 되면 that 변수에 생성할 인스턴스가 전달되고, 적절한 this가 growUp 함수에 전달될 수 있게 된다.

 

화살표 함수의 경우 this를 갖지 않아서 this를 자신의 상위 스코프에서 찾게 된다.

그래서 다음 예제의 경우 위 해결 방식과 같은 결과가 나타난다.

function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this|는 Person 객체를 참조
  }, 1000);
}

var p = new Person();

 

그 외의 제한점은 mdn 문서를 참고하면 될 것 같다.

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Functions/Arrow_functions


참고 : mdn

'front-end > JavaScript' 카테고리의 다른 글

[JavaScript] 이벤트1  (0) 2023.04.28
[JavaScript] Array.prototype.forEach , map, filter  (0) 2023.04.20
[JavaScript] 생성자 함수  (0) 2023.04.12
[JavaScript] 객체 리터럴  (0) 2023.04.10
[JavaScript] 타입 변환  (0) 2023.04.08