Skip to main content

같은 코드를 여러 번 쓰다 보면 어느 순간 이런 생각이 듭니다. "이거 복붙 말고 더 똑똑한 방법 없을까?" 자바스크립트의 함수(function) 는 바로 그때 등장하는 해결사입니다. 함수는 여러 줄의 코드를 하나의 이름으로 묶어 두고, 필요할 때마다 다시 사용할 수 있게 해줍니다. 그래서 코드는 짧아지고, 읽기 쉬워지고, 수정도 훨씬 편해집니다.1

이번 장에서는 함수를 처음 배우는 사람이 꼭 알아야 할 것들을 차근차근 살펴보겠습니다. 함수 선언, 매개변수와 인수, 반환값, 기본값, 화살표 함수, 그리고 스코프의 기초까지 익히면 코드를 훨씬 더 구조적으로 짤 수 있게 됩니다.

왜 함수가 필요할까

예를 들어, 사용자에게 인사 메시지를 보여주는 코드를 여러 곳에서 쓴다고 해 봅시다.

console.log("안녕하세요, 민지님!");
console.log("안녕하세요, 철수님!");
console.log("안녕하세요, 영희님!");

겉보기엔 별문제 없어 보이지만, 인사 형식을 바꾸고 싶어지면 모든 줄을 직접 고쳐야 합니다. 이런 중복은 프로그램이 커질수록 큰 짐이 됩니다. 함수는 이런 반복을 줄이기 위해 존재합니다.1

function greet(name) {
  console.log("안녕하세요, " + name + "님!");
}

greet("민지");
greet("철수");
greet("영희");

이제 인사 방식이 바뀌어도 greet 함수만 수정하면 됩니다. 코드가 훨씬 정리되어 보이죠. 함수는 단순히 "짧게 쓰는 기술"이 아니라, 코드를 의미 있는 단위로 나누는 방법입니다.

함수 선언과 호출

함수를 만드는 가장 기본적인 방법은 함수 선언(function declaration) 입니다.1

function sayHello() {
  console.log("안녕하세요!");
}

이 코드는 함수를 선언한 것입니다. 아직 실행되지는 않았습니다. 함수를 실제로 실행하려면 이름 뒤에 괄호를 붙여 호출해야 합니다.

sayHello();

함수의 기본 모양은 이렇습니다.

function 함수이름(매개변수들) {
  // 실행할 코드
}

여기서 중요한 점은, 함수는 한 번 만들어 두면 여러 번 호출할 수 있다는 것입니다.

function sayHello() {
  console.log("안녕하세요!");
}

sayHello();
sayHello();
sayHello();

같은 동작을 반복해야 할 때 함수는 아주 강력합니다. 반복문이 "같은 작업을 여러 번 돌리는 도구"였다면, 함수는 "그 작업 자체를 이름 붙여 보관하는 도구"라고 생각하면 됩니다.

매개변수와 인수

함수는 외부에서 값을 받아서 동작을 바꿀 수 있습니다. 이때 등장하는 것이 매개변수(parameter) 와 인수(argument) 입니다.2

function greet(name) {
  console.log("안녕하세요, " + name + "님!");
}

greet("지수");

여기서 name은 매개변수입니다. 함수를 만들 때 괄호 안에 적는 이름이죠. 그리고 "지수"는 인수입니다. 함수를 호출할 때 실제로 전달하는 값입니다.2

쉽게 말하면 이렇습니다.

  • 매개변수: 함수가 받을 값을 위한 자리

  • 인수: 실제로 그 자리에 넣는 값

둘을 헷갈리는 사람이 정말 많습니다. 하지만 익숙해지면 "함수 정의 쪽은 매개변수, 호출하는 쪽은 인수"라고 자연스럽게 구분하게 됩니다.

매개변수는 여러 개를 받을 수도 있습니다.

function add(a, b) {
  console.log(a + b);
}

add(3, 5);

이 함수에서 a, b는 매개변수이고, 3, 5는 인수입니다.

function introduce(name, age) {
  console.log("이름: " + name);
  console.log("나이: " + age);
}

introduce("민수", 20);

자바스크립트 함수는 매개변수의 자료형을 미리 적지 않습니다. 즉, 숫자를 받을지 문자를 받을지 함수 선언만 보고는 정해져 있지 않습니다.2 편리한 대신, 잘못된 값을 넣어도 자동으로 완벽히 막아 주지는 않기 때문에 호출할 때 주의가 필요합니다.

반환값과 return

함수는 일을 한 뒤에 결과를 돌려줄 수 있습니다. 이것을 반환값(return value) 이라고 합니다.3

function add(a, b) {
  return a + b;
}

let result = add(2, 3);
console.log(result);

add(2, 3)은 단순히 함수를 호출한 것이 아니라, 실행 결과로 5를 만들어 냅니다. 그래서 그 값을 result에 저장할 수 있습니다.

반환값은 "함수의 최종 결과물"이라고 생각하면 쉽습니다. 함수가 계산기라면, return은 계산 결과가 나오는 출구입니다.

function square(number) {
  return number * number;
}

console.log(square(4));

이 함수는 4를 받아 16을 돌려줍니다.

반환값은 다른 계산에 바로 넣을 수도 있습니다.

function multiply(a, b) {
  return a * b;
}

console.log(multiply(3, 4) + 10);

이 코드는 먼저 multiply(3, 4)가 12를 반환하고, 그다음 12 + 10이 계산되어 22가 됩니다.3

return은 함수를 끝낸다

return은 값을 돌려주는 역할도 하지만, 그 지점에서 함수 실행을 즉시 종료하기도 합니다.1

function checkAge(age) {
  if (age >= 20) {
    return "성인입니다.";
  }

  return "미성년자입니다.";
}

조건에 맞는 return을 만나면 함수는 거기서 끝납니다. 아래 코드는 더 이상 실행되지 않습니다.

function test() {
  console.log("시작");
  return "끝";
  console.log("이 코드는 실행되지 않음");
}

return이 없으면 무엇이 돌아올까

함수에 return이 없으면 자바스크립트는 기본적으로 undefined를 반환합니다.1

function sayHi() {
  console.log("안녕하세요");
}

let value = sayHi();
console.log(value); // undefined

이 점은 초보자가 자주 놓치는 부분입니다. 화면에 출력하는 것과 값을 반환하는 것은 다릅니다.

function add1(a, b) {
  console.log(a + b);
}

function add2(a, b) {
  return a + b;
}

add1()은 결과를 콘솔에 보여 주기만 하고, add2()는 결과를 밖으로 돌려줍니다. 둘은 비슷해 보여도 용도가 다릅니다.

기본값으로 더 안전한 함수 만들기

함수를 호출할 때 인수를 빠뜨리면, 해당 매개변수는 기본적으로 undefined가 됩니다.2

function greet(name) {
  console.log("안녕하세요, " + name + "님!");
}

greet();

이 경우 name은 undefined가 되어 어색한 결과가 나올 수 있습니다. 그래서 자바스크립트는 기본 매개변수(default parameter) 문법을 제공합니다.4

function greet(name = "손님") {
  console.log(`안녕하세요, ${name}!`);
}

greet();
greet("수아");

출력 결과는 다음과 같습니다.

안녕하세요, 손님!
안녕하세요, 수아!

기본값은 인수가 없을 때, 또는 undefined가 들어왔을 때 사용됩니다.4

function multiply(a, b = 1) {
  return a * b;
}

console.log(multiply(5)); // 5
console.log(multiply(5, 3)); // 15
console.log(multiply(5, undefined)); // 5

하지만 null은 다릅니다. null은 "비어 있음"이라는 실제 값이기 때문에 기본값을 자동으로 대신 쓰지 않습니다.4

function test(value = 10) {
  console.log(value);
}

test(); // 10
test(undefined); // 10
test(null); // null

기본값은 다른 매개변수를 이용해 만들 수도 있습니다.4

function makeMessage(name, greeting = "안녕", message = greeting + ", " + name) {
  return message;
}

console.log(makeMessage("지훈"));

이런 기능은 꽤 편리하지만, 초보자라면 처음에는 "없으면 대신 넣을 값" 정도로 이해해도 충분합니다.

화살표 함수

자바스크립트에는 함수를 더 짧게 쓰는 방법도 있습니다. 바로 화살표 함수(arrow function) 입니다.5

const add = (a, b) => {
  return a + b;
};

이 함수는 일반 함수 표현식과 비슷한 역할을 합니다. 다만 문법이 더 간결합니다.5

특히 한 줄로 결과를 바로 반환할 때 많이 사용합니다.

const add = (a, b) => a + b;

중괄호 {}를 생략하면 return도 함께 생략된 것으로 처리됩니다. 이것을 암시적 반환이라고 생각하면 됩니다.5

화살표 함수 문법 규칙

초보자가 가장 많이 헷갈리는 부분만 정리해 보면 이렇습니다.

  • 매개변수가 하나면 괄호를 생략할 수 있습니다.

  • 매개변수가 없으면 괄호가 꼭 필요합니다.

  • 실행문이 여러 줄이면 중괄호와 return을 직접 써야 합니다.5

예제를 보면 금방 감이 옵니다.

const square = x => x * x;
const sayHello = () => "안녕하세요";
const divide = (a, b) => {
  return a / b;
};

배열 메서드와 함께 쓰면 특히 깔끔합니다.

const numbers = [1, 2, 3, 4];
const doubled = numbers.map(number => number * 2);

console.log(doubled);

화살표 함수를 쓸 때 주의할 점

화살표 함수는 편리하지만 만능은 아닙니다. 가장 중요한 차이 중 하나는 자기만의 this를 가지지 않는다는 점입니다.5 이 장에서는 this를 깊게 다루지 않지만, 초보자라면 일단 이렇게 기억하면 충분합니다.

짧은 계산 함수나 콜백에는 잘 어울리지만, 객체의 메서드에는 조심해서 써야 한다는 것입니다.5

const person = {
  name: "민지",
  greet: () => {
    console.log(this.name);
  }
};

이 코드는 기대와 다르게 동작할 수 있습니다. 그래서 객체 안에서 메서드를 만들 때는 보통 일반 함수를 더 많이 사용합니다.

const person = {
  name: "민지",
  greet() {
    console.log(this.name);
  }
};

지금 단계에서는 이렇게만 기억해도 충분합니다. 짧고 간단한 함수엔 화살표 함수, 객체 메서드엔 일반 함수부터 생각하기.

스코프의 기초

함수를 배우면서 꼭 함께 알아야 하는 개념이 스코프(scope) 입니다. 스코프는 아주 간단히 말해, 변수에 접근할 수 있는 범위입니다.6

지역 변수와 전역 변수

함수 안에서 만든 변수는 그 함수 안에서만 사용할 수 있습니다. 이런 변수를 지역 변수라고 합니다.6

function test() {
  let message = "안녕하세요";
  console.log(message);
}

test();
// console.log(message); // 오류

message는 함수 바깥에서는 보이지 않습니다.

반대로 함수 밖에서 만든 변수는 전역 변수라고 하며, 함수 안에서도 접근할 수 있습니다.6

let userName = "지민";

function showName() {
  console.log(userName);
}

showName();

바깥 변수 읽기

함수는 자기 바깥에 있는 변수를 읽을 수 있습니다.6

let fruit = "사과";

function printFruit() {
  console.log("좋아하는 과일: " + fruit);
}

printFruit();

이런 동작은 자연스럽고 편리하지만, 너무 많은 전역 변수에 의존하면 코드가 복잡해질 수 있습니다. 함수는 가능하면 필요한 값을 매개변수로 전달받는 방식이 더 깔끔합니다.

같은 이름의 변수는 가까운 것이 우선

함수 안에 바깥 변수와 같은 이름의 변수가 있으면, 함수 안의 변수가 우선합니다. 이것을 보통 "가린다" 또는 "덮어쓴다"라고 이해하면 됩니다.6

let userName = "철수";

function showName() {
  let userName = "영희";
  console.log(userName);
}

showName(); // 영희
console.log(userName); // 철수

함수 안의 userName은 지역 변수이고, 바깥의 userName은 전역 변수입니다. 둘은 이름은 같지만 서로 다른 변수입니다.

함수를 잘 만드는 작은 습관

함수는 많이 만들수록 실력이 늘지만, 처음부터 몇 가지 습관을 들이면 훨씬 좋습니다.

  • 함수 이름은 동작이 드러나게 짓습니다. 예를 들어 calc보다 calculateTotal이 더 이해하기 쉽습니다.

  • 함수 하나에는 가능하면 한 가지 역할만 맡깁니다.

  • 전역 변수에 너무 의존하지 말고, 필요한 값은 매개변수로 받는 연습을 합니다.

  • 결과가 필요하면 console.log()만 하지 말고 return도 함께 생각합니다.

예를 들어 아래 함수는 이름도 분명하고, 입력값도 받고, 결과도 반환합니다.

function calculateDiscountPrice(price, discountRate = 0.1) {
  return price - price * discountRate;
}

let finalPrice = calculateDiscountPrice(10000);
console.log(finalPrice);

이런 함수는 나중에 어디서든 다시 사용하기 좋습니다.

자주 하는 실수

함수를 처음 배울 때 특히 자주 나오는 실수가 있습니다.

  • return 없이 값을 돌려준다고 착각하기

  • 매개변수와 인수를 뒤섞어 부르기

  • 함수 안의 지역 변수를 바깥에서도 쓸 수 있다고 생각하기

  • 화살표 함수를 모든 곳에서 똑같이 써도 된다고 믿기

예를 들어 아래 코드는 초보자가 자주 만드는 실수입니다.

function add(a, b) {
  a + b;
}

let result = add(2, 3);
console.log(result);

겉으로는 더하기를 했으니 5가 나올 것 같지만, 실제로는 undefined가 출력됩니다. 이유는 return이 없기 때문입니다.

올바른 코드는 이렇게 써야 합니다.

function add(a, b) {
  return a + b;
}

또 하나의 흔한 실수는 함수 바깥 변수에 너무 의존하는 것입니다.

let price = 10000;

function getTax() {
  return price * 0.1;
}

이 코드는 동작은 하지만, price가 바뀌면 함수 결과도 함께 바뀝니다. 함수가 바깥 환경에 묶여 있는 셈이죠. 더 좋은 방식은 값을 매개변수로 받는 것입니다.

function getTax(price) {
  return price * 0.1;
}

이제 함수는 더 독립적이고 재사용하기 쉬워집니다.

직접 읽어 보는 예제

지금까지 배운 내용을 하나의 예제로 묶어 보겠습니다.

function makeOrderMessage(item, count = 1) {
  const message = item + "을(를) " + count + "개 주문했습니다.";
  return message;
}

console.log(makeOrderMessage("커피"));
console.log(makeOrderMessage("샌드위치", 2));

이 코드에는 중요한 요소가 모두 들어 있습니다.

  • makeOrderMessage는 함수 이름입니다.

  • item, count는 매개변수입니다.

  • count = 1은 기본값입니다.

  • 함수 안의 message는 지역 변수입니다.

  • return은 최종 결과를 호출한 곳으로 돌려줍니다.

같은 기능을 화살표 함수로 바꾸면 이렇게 쓸 수도 있습니다.

const makeOrderMessage = (item, count = 1) => {
  const message = item + "을(를) " + count + "개 주문했습니다.";
  return message;
};

둘 다 같은 역할을 합니다. 지금 단계에서는 둘 중 하나만 고집할 필요는 없습니다. 먼저 일반 함수 문법에 익숙해지고, 점차 화살표 함수도 자연스럽게 읽을 수 있으면 충분합니다.

마무리

함수는 자바스크립트에서 정말 중요한 도구입니다. 긴 코드를 잘게 나누고, 같은 동작을 여러 번 재사용하며, 프로그램을 이해하기 쉬운 덩어리로 만들어 줍니다.1

이번 장에서 꼭 기억할 핵심은 다음과 같습니다.

  • 함수는 코드를 묶어 두었다가 필요할 때 호출하는 도구입니다.

  • 매개변수는 함수가 받는 이름표이고, 인수는 실제로 전달하는 값입니다.2

  • return은 값을 돌려주며, 함수 실행을 끝냅니다.1

  • 기본값을 사용하면 빠진 인수 때문에 생기는 문제를 줄일 수 있습니다.4

  • 화살표 함수는 짧고 편리하지만, 모든 상황에 무조건 맞는 것은 아닙니다.5

  • 함수 안의 변수는 보통 함수 안에서만 보인다는 점을 기억해야 합니다.6

다음 장에서는 이렇게 만든 함수와 함께 자주 쓰게 되는 배열과 객체를 배웁니다. 이제 코드를 "한 줄씩 쓰는 단계"에서, "의미 있는 단위로 설계하는 단계"로 한 걸음 올라선 셈입니다.

참고

2JavaScript Function Parameters

3Function return values - Learn web development | MDN

4Default parameters - JavaScript | MDN

5Arrow function expressions - JavaScript | MDN

책 목록

처음부터 제대로 배우는 JavaScript 기초

전체 목차 보기

이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.

틸노트는 사용자가 AI를 활용해 노트를 쉽게 작성하거나 편집할 수 있는 서비스입니다.

AI 스퀘어 단톡방에 함께해요

AI 활용과 틸노트 사용 팁을 나누는 오픈채팅방입니다. 입장 비밀번호는 tilnote입니다.

참여하기