본문으로 건너뛰기
기술스택 · stack/javascript/함수를 값처럼: 함수 표현식 · 콜백 · 화살표 함수

JavaScript · 2장 기본

함수를 값처럼: 함수 표현식 · 콜백 · 화살표 함수

자바스크립트에서 함수는 숫자나 문자열처럼 변수에 담고, 다른 함수에 건네줄 수 있는 값이에요. 이 성질 덕분에 "버튼을 누르면 이 함수를 불러 줘", "배열의 항목마다 이 함수를 적용해 줘" 같은 코드를 쓸 수 있어요.

#2.10

01. 함수도 값이에요: 함수 표현식

앞 글의 function 이름() {}은 함수 선언문이에요. 함수를 만들어 변수에 담는 함수 표현식도 있어요. 담긴 변수 이름으로 부르는 방법은 똑같아요.

const vat = function (price) {
  return price * 0.1;
};

console.log(vat(20000));    // 2000
console.log(typeof vat);    // function
const tax = vat;            // 다른 이름에 그대로 담을 수도 있어요
console.log(tax(5000));     // 500

둘의 차이는 언제부터 부를 수 있느냐예요. 함수 선언문은 엔진이 코드를 실행하기 전에 미리 준비해 둬서, 선언한 줄보다 위에서도 부를 수 있어요(호이스팅). 함수 표현식은 const 변수이니 그 줄을 지난 뒤에만 쓸 수 있어요.

console.log(greet('하늘'));   // 안녕, 하늘 — 선언문은 위에서도 돼요

function greet(name) {
  return '안녕, ' + name;
}

console.log(shout('바다'));   // 표현식은 안 돼요
const shout = function (name) {
  return name + '!!';
};

02. 함수를 건네주는 콜백

함수가 값이니 다른 함수의 인자로 넣을 수 있어요. 이렇게 건네져서 나중에 불리는 함수를 콜백(callback, 다시 불러 줄 함수)이라고 해요. 받는 쪽은 "무엇을 할지"를 몰라도 "언제 할지"만 정하면 되니, 하나의 함수를 여러 용도로 쓸 수 있어요.

function repeat(times, action) {
  for (let i = 1; i <= times; i++) {
    action(i);                 // 건네받은 함수를 불러요
  }
}

function sayHi(n) {
  console.log(`${n}번째 안녕`);
}

repeat(3, sayHi);              // sayHi를 부르지 않고 그대로 건네요
①repeat(3, sayHi)는 sayHi라는 함수 자체를 action으로 받아요. repeat 안의 반복이 action(1) · action(2) · action(3)을 부를 때마다 sayHi가 실행돼요.

콜백은 자바스크립트 어디에나 있어요. 정해진 시간 뒤에 부르는 setTimeout, 배열의 항목마다 부르는 map · filter(5장), 버튼을 누를 때 부르는 이벤트 리스너(2부)가 모두 콜백을 받아요.

setTimeout(function () {
  console.log('0.1초 뒤에 불렸어요');
}, 100);

console.log('먼저 실행돼요');

03. 화살표 함수

콜백처럼 짧은 함수를 자주 쓰다 보니 더 짧은 문법이 생겼어요. function 대신 =>를 쓰는 화살표 함수예요.

  • 매개변수가 하나면 괄호를 뺄 수 있어요: n => n * 2
  • 본문이 식 하나면 중괄호와 return을 뺄 수 있어요. 그 식의 값이 돌아가요.
  • 본문이 여러 줄이면 중괄호를 쓰고, 이때는 return을 직접 써야 해요.
const double = n => n * 2;
const add = (a, b) => a + b;
const shipping = amount => {
  if (amount >= 50000) return 0;
  return 3000;
};

console.log(double(4), add(2, 3), shipping(42000)); // 8 5 3000

setTimeout(() => console.log('화살표 콜백'), 0);

함정이 하나 있어요. 객체를 바로 돌려주려고 => { name: … }라고 쓰면, 엔진은 중괄호를 객체가 아니라 함수 본문으로 읽어요. 그래서 undefined가 나와요. 객체를 돌려줄 땐 괄호로 감싸요.

const makeItem = name => ({ name, qty: 1 });
const broken = name => { name: name };

console.log(makeItem('연필')); // { name: '연필', qty: 1 }
console.log(broken('연필'));   // undefined

화살표 함수에는 자기만의 this가 없다는 차이도 있어요. 객체의 메서드를 만들 때 이 차이가 중요해지는데, 4장과 6장에서 다뤄요.

"안녕!"이 0.1초 뒤에 나오게 하려고 했는데, 바로 나와 버려요. 출력 순서가 기다리는 중 → 안녕!이 되게 한 곳만 고쳐 보세요.

function hello() {
  console.log('안녕!');
}

setTimeout(hello(), 100);
console.log('기다리는 중');
해답 보기

hello()는 함수를 그 자리에서 불러서 그 결과(undefined)를 setTimeout에 넘겨요. 함수 자체를 건네려면 괄호를 빼요.

setTimeout(hello, 100);

인자를 넣어 불러야 한다면 setTimeout(() => hello('하늘'), 100)처럼 화살표 함수로 감싸서 건네요.

04. 실전 포인트

  • 언제 쓰나요? 콜백과 짧은 계산은 화살표 함수가 기본이에요(prices.map(p => p * 2)). 파일의 주요 함수처럼 이름이 중요하고 여러 곳에서 부르는 함수는 함수 선언문이나 const + 화살표 함수 중 팀 규칙을 따라요.
  • 대신 쓰는 것: 객체의 메서드에는 화살표 함수를 쓰지 않아요(this 문제, 4장). 콜백이 길어지면 이름 있는 함수로 빼서 건네요. 읽기도 쉽고 오류 메시지에 이름이 나와 디버깅도 쉬워요.
  • 흔한 실수: 콜백 자리에 hello()처럼 괄호를 붙여 바로 불러 버리는 것, 중괄호 본문에서 return을 빼먹는 것, 객체를 돌려주며 괄호를 빼먹는 것이에요.

정리

  • 함수는 값이라 변수에 담고(함수 표현식) 인자로 건넬 수 있어요. 선언문은 위에서도, 표현식은 그 줄 뒤에서만 불러요.
  • 건네져서 나중에 불리는 함수가 콜백이에요. 건넬 땐 괄호 없이 함수 자체를 넘겨요.
  • 화살표 함수 (a, b) => a + b는 식 하나면 그 값을 돌려주고, 중괄호 본문이면 return을 직접 써요.
  • 객체를 바로 돌려줄 땐 () => ({ … })처럼 괄호로 감싸요.
SIMPLE · 기술스택 / JavaScript — 2장 기본