최근 본 글

    자바스크립트 함수 사용법 – 기본 함수와 화살표 함수 차이

    자바스크립트 함수 사용법 – 기본 함수와 화살표 함수 차이

    지난 글에서는 조건문과 반복문을 배우며 프로그램이 스스로 판단하고 같은 일을 반복하게 만드는 방법을 알아보았습니다. 성적표 실습처럼 코드가 점점 길어지다 보면 한 가지 고민이 생깁니다. “학점을 계산하는 코드를 다른 곳에서도 또 써야 하는데, 똑같이 복사해서 붙여넣어야 할까?” 만약 복사한 코드가 열 군데에 퍼져 있는데 학점 기준이 바뀐다면, 열 군데를 모두 찾아 고쳐야 합니다. 이 문제를 해결하는 것이 바로 함수(Function)입니다. 오늘은 함수를 만들고 사용하는 기본 방법부터 매개변수와 return, 그리고 요즘 코드에서 자주 보이는 화살표 함수와 기본 함수의 차이까지 예제로 정리해 보겠습니다.

    1. 함수란 무엇인가요?

    함수는 특정 작업을 수행하는 코드를 하나로 묶어 이름을 붙여 둔 것입니다. 한 번 만들어 두면 이름만 불러서 몇 번이고 다시 사용할 수 있습니다.

    자판기를 떠올리면 이해가 쉽습니다. 자판기에 돈과 버튼 선택이라는 입력을 넣으면, 안에서 정해진 과정을 거쳐 음료라는 결과가 나옵니다. 우리는 자판기 내부가 어떻게 작동하는지 몰라도 버튼만 누르면 매번 같은 방식으로 음료를 받을 수 있습니다. 함수도 마찬가지로 값을 넣으면 정해진 작업을 거쳐 결과를 돌려줍니다.

    입력
    매개변수
    →
    함수
    정해진 작업 수행
    →
    출력
    return 값

    사실 우리는 이미 함수를 사용해 왔습니다. 값을 콘솔에 출력하는 console.log(), 문자열을 숫자로 바꾸는 Number()가 모두 자바스크립트가 미리 만들어 둔 함수입니다. 오늘은 이런 함수를 직접 만드는 방법을 배웁니다.

    2. 함수를 쓰면 좋은 이유

    • 재사용 : 같은 코드를 여러 번 쓰지 않고, 한 번 만든 함수를 필요할 때마다 부르면 됩니다.
    • 수정이 쉬움 : 기준이 바뀌면 함수 한 곳만 고치면 그 함수를 쓰는 모든 곳에 반영됩니다. CSS 편에서 외부 스타일 시트 하나만 고치면 모든 페이지가 바뀌던 것과 같은 원리입니다.
    • 읽기 쉬움 : calculateTotal()처럼 이름만 봐도 무슨 일을 하는지 알 수 있어, 긴 코드가 짧은 이야기처럼 읽힙니다.
    • 문제 찾기가 쉬움 : 기능별로 나뉘어 있어 오류가 생겼을 때 어느 함수에서 문제가 생겼는지 범위를 좁히기 쉽습니다.

    3. 함수 만들기와 호출하기

    가장 기본적인 함수 만드는 방법을 함수 선언문이라고 합니다. function 키워드 뒤에 함수 이름, 괄호, 중괄호를 차례로 씁니다.

    // 함수 만들기 (선언)
    function sayHello() {
      console.log("안녕하세요!");
      console.log("자바스크립트 공부 중입니다.");
    }
    
    // 함수 사용하기 (호출)
    sayHello();
    sayHello();

    여기서 꼭 구분해야 할 두 가지 개념이 있습니다. 함수를 만드는 것(선언)과 실행하는 것(호출)입니다. 함수를 만들기만 하면 아무 일도 일어나지 않습니다. 레시피를 적어 둔 것만으로는 요리가 완성되지 않는 것과 같습니다. 함수 이름 뒤에 괄호()를 붙여 호출해야 비로소 안의 코드가 실행됩니다. 위 코드는 sayHello를 두 번 호출했으므로 두 문장이 두 번씩 출력됩니다.

    4. 매개변수와 인수 – 함수에 값 전달하기

    앞의 함수는 항상 똑같은 말만 합니다. 함수에 값을 전달해 매번 다른 결과를 얻고 싶다면 괄호 안에 매개변수를 적습니다.

    function greet(name) {
      console.log(`${name}님, 안녕하세요!`);
    }
    
    greet("홍길동");  // 홍길동님, 안녕하세요!
    greet("김철수");  // 김철수님, 안녕하세요!

    함수를 만들 때 괄호 안에 적는 name을 매개변수(parameter), 함수를 호출할 때 실제로 넣는 "홍길동"을 인수(argument)라고 부릅니다. 매개변수는 값을 받기 위해 비워 둔 빈 그릇이고, 인수는 그 그릇에 실제로 담기는 내용물이라고 생각하면 됩니다.

    매개변수는 쉼표로 구분해 여러 개 만들 수 있습니다. 이때 인수는 순서대로 매개변수에 들어갑니다.

    function introduce(name, age, city) {
      console.log(`${city}에 사는 ${age}살 ${name}입니다.`);
    }
    
    introduce("홍길동", 25, "전주");
    // 전주에 사는 25살 홍길동입니다.

    인수를 빠뜨리면 해당 매개변수에는 지난 글에서 배운 undefined가 들어갑니다. 이를 대비해 매개변수에 기본값을 지정해 둘 수도 있습니다.

    function greet(name = "방문자") {
      console.log(`${name}님, 안녕하세요!`);
    }
    
    greet("홍길동");  // 홍길동님, 안녕하세요!
    greet();          // 방문자님, 안녕하세요!

    5. return – 함수의 결과 돌려받기

    지금까지 만든 함수는 결과를 콘솔에 출력하기만 했습니다. 하지만 대부분의 함수는 계산한 결과를 호출한 곳으로 돌려주어 다른 곳에서 활용할 수 있게 해야 합니다. 이때 사용하는 것이 return입니다.

    function add(a, b) {
      return a + b;
    }
    
    const result = add(3, 5);
    console.log(result);           // 8
    console.log(add(10, 20) * 2);  // 60

    add(3, 5)를 호출하면 함수 안에서 계산한 8이 return되어, 함수를 호출한 자리가 8이라는 값으로 바뀐다고 생각하면 됩니다. 그래서 결과를 변수에 저장하거나, add(10, 20) * 2처럼 다른 계산에 바로 이어서 사용할 수 있습니다.

    return과 console.log의 차이는 초보자가 가장 많이 헷갈리는 부분입니다. console.log는 값을 화면(콘솔)에 보여주기만 할 뿐, 그 값을 프로그램이 다시 사용할 수는 없습니다. 반면 return은 값을 돌려주어 다음 계산에 쓸 수 있게 합니다. 계산기에 비유하면 console.log는 화면에 숫자를 띄우는 것이고, return은 그 숫자를 다음 계산에 넘겨주는 것입니다.

    function addLog(a, b) {
      console.log(a + b);   // 출력만 함
    }
    
    const x = addLog(3, 5);  // 콘솔에 8이 찍히지만
    console.log(x);          // undefined ← 돌려받은 값이 없음!

    또한 return을 만나면 함수는 그 즉시 종료됩니다. return 아래에 있는 코드는 실행되지 않습니다. 이 성질을 이용해 조건에 맞지 않으면 일찍 끝내는 방식으로도 자주 사용합니다.

    function getGrade(score) {
      if (score >= 90) return "A";
      if (score >= 80) return "B";
      if (score >= 70) return "C";
      return "F";
    }
    
    console.log(getGrade(85));  // B

    지난 글의 성적표에서 if…else if로 작성했던 학점 계산을 함수로 만든 것입니다. 85점이면 두 번째 줄에서 “B”를 return하고 함수가 끝나기 때문에 else를 쓰지 않아도 아래 조건은 검사되지 않습니다. 이제 학점이 필요한 곳 어디서든 getGrade(점수)만 부르면 됩니다.

    6. 함수 표현식 – 함수를 변수에 담기

    자바스크립트에서는 함수도 숫자나 문자열처럼 값으로 취급됩니다. 그래서 함수를 변수에 담을 수도 있는데, 이것을 함수 표현식이라고 합니다.

    // 함수 선언문
    function multiply(a, b) {
      return a * b;
    }
    
    // 함수 표현식
    const multiply2 = function (a, b) {
      return a * b;
    };
    
    console.log(multiply(3, 4));   // 12
    console.log(multiply2(3, 4));  // 12

    두 방식 모두 결과는 같습니다. 함수 표현식은 function 뒤에 이름 없이 바로 괄호가 오고, 그 함수를 const 변수에 담는다는 점이 다릅니다. 이 함수 표현식을 더 짧게 줄인 것이 바로 다음에 배울 화살표 함수입니다.

    7. 화살표 함수 – 더 짧고 간결하게

    화살표 함수(Arrow Function)는 function 키워드 대신 => 기호를 사용해 함수를 짧게 쓰는 방법입니다. 모양이 화살표처럼 생겨서 붙은 이름입니다. 요즘 작성되는 자바스크립트 코드에서는 화살표 함수를 매우 자주 볼 수 있습니다.

    // 함수 표현식
    const add1 = function (a, b) {
      return a + b;
    };
    
    // 화살표 함수
    const add2 = (a, b) => {
      return a + b;
    };

    function을 지우고 괄호와 중괄호 사이에 =>를 넣은 것뿐입니다. 그런데 화살표 함수는 조건에 따라 더 짧게 줄일 수 있습니다.

    ① 실행할 코드가 return 한 줄뿐이면 중괄호와 return을 생략

    const add3 = (a, b) => a + b;
    console.log(add3(2, 3));  // 5

    중괄호 없이 화살표 뒤에 값을 바로 쓰면, 그 값이 자동으로 return됩니다. 세 줄이었던 함수가 한 줄로 줄었습니다.

    ② 매개변수가 하나뿐이면 괄호도 생략 가능

    const double = n => n * 2;
    console.log(double(7));  // 14

    ③ 매개변수가 없으면 빈 괄호는 반드시 써야 함

    const sayHi = () => console.log("안녕하세요!");
    sayHi();

    같은 기능의 함수가 어떻게 짧아지는지 한눈에 비교해 보겠습니다.

    선언문   function square(n) { return n * n; }
    표현식   const square = function (n) { return n * n; };
    화살표   const square = (n) => { return n * n; };
    최대 축약 const square = n => n * n;

    단, 생략은 선택 사항입니다. 처음에는 괄호와 중괄호를 모두 쓰는 형태로 연습하다가, 익숙해지면 점차 줄여 쓰는 것을 추천합니다. 너무 줄이면 오히려 읽기 어려워질 수 있으니 팀이나 스스로 정한 규칙에 맞춰 일관되게 쓰는 것이 중요합니다.

    8. 기본 함수와 화살표 함수의 차이

    화살표 함수는 단순히 짧게 쓰는 문법만이 아니라, 동작에도 몇 가지 차이가 있습니다. 입문 단계에서 알아두면 좋은 두 가지를 정리해 보겠습니다.

    ① 호출할 수 있는 시점 (호이스팅)
    함수 선언문은 코드에서 함수를 만든 위치보다 위에서 호출해도 정상적으로 동작합니다. 자바스크립트가 실행 전에 선언문으로 만든 함수를 미리 준비해 두기 때문인데, 이를 호이스팅(끌어올림)이라고 부릅니다. 반면 변수에 담는 함수 표현식과 화살표 함수는 그 변수가 만들어진 아래에서만 호출할 수 있습니다.

    hello1();  // 정상 실행 ✔
    function hello1() {
      console.log("선언문 함수");
    }
    
    hello2();  // 오류! ✘ Cannot access 'hello2' before initialization
    const hello2 = () => {
      console.log("화살표 함수");
    };

    그래서 화살표 함수를 쓸 때는 함수를 먼저 만들고 그 아래에서 호출하는 순서를 지켜야 합니다. 사실 이 순서는 어떤 방식이든 코드를 읽기 쉽게 만드는 좋은 습관입니다.

    ② this의 동작
    this는 “지금 이 함수를 실행하는 주인”을 가리키는 특별한 키워드입니다. 기본 함수는 어떻게 호출되었느냐에 따라 this가 달라지지만, 화살표 함수는 자신만의 this를 가지지 않고 바깥쪽의 this를 그대로 사용합니다. this는 객체와 이벤트를 더 배운 뒤에 자세히 다룰 내용이므로, 지금은 “객체 안에서 메서드를 만들 때는 기본 함수를, 그 외의 짧은 함수에는 화살표 함수를 주로 쓴다” 정도로 기억해 두면 충분합니다.

    구분 함수 선언문 화살표 함수
    문법function 이름() { }const 이름 = () => { }
    코드 길이상대적으로 김짧고 간결함
    선언 전 호출가능 (호이스팅)불가능
    this호출 방식에 따라 달라짐바깥쪽 this를 그대로 사용
    주로 쓰는 곳주요 기능 함수, 객체 메서드짧은 계산, 이벤트 처리, 배열 함수

    둘 중 무엇이 더 좋다기보다는 상황에 맞게 골라 쓰는 것입니다. 입문 단계에서는 두 방식을 모두 읽을 수 있고, 같은 함수를 두 방식으로 바꿔 쓸 수 있는 정도면 충분합니다.

    9. 변수의 유효 범위 – 스코프

    함수를 사용할 때 알아야 할 중요한 개념이 하나 더 있습니다. 바로 스코프(Scope), 즉 변수가 살아 있는 범위입니다.

    const siteName = "코딩 공부";   // 전역 변수: 어디서든 사용 가능
    
    function showInfo() {
      const author = "홍길동";       // 지역 변수: 함수 안에서만 사용 가능
      console.log(siteName);        // 코딩 공부 ✔
      console.log(author);          // 홍길동 ✔
    }
    
    showInfo();
    console.log(author);            // 오류! ✘ author is not defined
    • 전역 변수 : 함수 바깥에서 만든 변수로, 코드 어디에서든 사용할 수 있습니다.
    • 지역 변수 : 함수 안(중괄호 안)에서 만든 변수로, 그 함수 안에서만 사용할 수 있습니다.

    함수는 바깥의 변수를 볼 수 있지만, 바깥에서는 함수 안의 변수를 볼 수 없습니다. 선팅된 자동차 유리처럼 안에서는 밖이 보이지만 밖에서는 안이 보이지 않는다고 생각하면 됩니다. 이 덕분에 서로 다른 함수에서 같은 이름의 변수를 써도 충돌하지 않습니다. 전역 변수를 많이 만들면 이름이 겹치거나 어디서 값이 바뀌었는지 추적하기 어려워지므로, 변수는 필요한 곳 안에서 만드는 것이 좋은 습관입니다.

    10. 함수 이름 잘 짓는 법

    지난 글에서 배운 변수 이름 규칙(카멜 케이스, 숫자로 시작 금지 등)은 함수에도 그대로 적용됩니다. 여기에 함수만의 관례가 하나 더 있습니다. 함수는 어떤 동작을 하는 것이므로 이름을 동사로 시작하는 것이 좋습니다.

    • get + 대상 : 값을 구해 돌려줄 때 → getGrade, getUserName
    • calculate + 대상 : 계산할 때 → calculateTotal, calculateAge
    • show, print + 대상 : 화면에 보여줄 때 → showMessage
    • is, has + 상태 : 참/거짓을 돌려줄 때 → isAdult, hasCoupon

    또 하나의 원칙은 함수 하나는 한 가지 일만 하게 만드는 것입니다. 계산도 하고, 출력도 하고, 저장도 하는 거대한 함수보다 각각의 일을 하는 작은 함수 여러 개가 훨씬 이해하기 쉽고 재사용하기도 좋습니다.

    11. 실습: 함수로 쇼핑몰 결제 금액 계산기 만들기

    오늘 배운 내용을 모두 활용해 장바구니 결제 금액을 계산하는 프로그램을 만들어 보겠습니다. 각 기능을 작은 함수로 나누고, 선언문과 화살표 함수를 함께 사용했습니다. 아래 코드를 cart.html로 저장해 브라우저에서 열고 콘솔을 확인해 보세요.

    <!DOCTYPE html>
    <html lang="ko">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>결제 금액 계산기</title>
    </head>
    <body>
      <h1>F12를 눌러 콘솔을 확인하세요</h1>
    
      <script>
        // 숫자를 1,000원 형식으로 바꾸는 함수 (화살표 함수)
        const formatPrice = price => price.toLocaleString() + "원";
    
        // 상품 하나의 금액 계산 (화살표 함수)
        const getItemTotal = (price, count) => price * count;
    
        // 할인 금액 계산 (선언문, 기본값 사용)
        function getDiscount(total, isMember = false) {
          if (isMember) {
            return total * 0.1;   // 회원 10% 할인
          }
          return 0;
        }
    
        // 배송비 계산 (선언문)
        function getShippingFee(total) {
          if (total >= 50000) return 0;  // 5만 원 이상 무료배송
          return 3000;
        }
    
        // 전체 결제 금액 계산 (다른 함수들을 조합)
        function calculatePayment(cart, isMember) {
          let subtotal = 0;
    
          console.log("===== 장바구니 =====");
          for (const item of cart) {
            const itemTotal = getItemTotal(item.price, item.count);
            subtotal += itemTotal;
            console.log(`${item.name} x ${item.count}개 = ${formatPrice(itemTotal)}`);
          }
    
          const discount = getDiscount(subtotal, isMember);
          const shipping = getShippingFee(subtotal - discount);
          const total = subtotal - discount + shipping;
    
          console.log("====================");
          console.log(`상품 금액: ${formatPrice(subtotal)}`);
          console.log(`회원 할인: -${formatPrice(discount)}`);
          console.log(`배송비: ${formatPrice(shipping)}`);
          console.log(`최종 결제 금액: ${formatPrice(total)}`);
    
          return total;
        }
    
        // 장바구니 데이터 (객체 배열)
        const myCart = [
          { name: "무선 마우스", price: 25000, count: 1 },
          { name: "마우스 패드", price: 8000, count: 2 },
          { name: "USB 허브", price: 15000, count: 1 }
        ];
    
        // 함수 호출
        calculatePayment(myCart, true);
      </script>
    </body>
    </html>

    콘솔에는 다음과 같은 결과가 출력됩니다.

    ===== 장바구니 =====
    무선 마우스 x 1개 = 25,000원
    마우스 패드 x 2개 = 16,000원
    USB 허브 x 1개 = 15,000원
    ====================
    상품 금액: 56,000원
    회원 할인: -5,600원
    배송비: 0원
    최종 결제 금액: 50,400원

    이 코드의 핵심은 calculatePayment 함수가 직접 모든 계산을 하지 않고, 작은 함수들을 불러서 조합한다는 점입니다. 나중에 회원 할인율이 15%로 바뀌면 getDiscount 함수만, 무료배송 기준이 바뀌면 getShippingFee 함수만 고치면 됩니다. 또한 장바구니 데이터는 지난 글에서 맛보기로 본 객체를 배열에 담은 형태로, item.price처럼 점을 찍어 각 정보를 꺼냈습니다. toLocaleString()은 숫자에 천 단위 쉼표를 넣어 주는 자바스크립트 내장 함수입니다.

    마지막 줄의 true를 false로 바꿔 비회원으로 계산해 보세요. 할인이 사라지면서 결제 금액이 5만 원을 넘어 무료배송이 그대로 적용되는 것을 확인할 수 있습니다. 상품을 하나 빼서 5만 원 미만으로 만들면 배송비 3,000원이 붙는 것도 확인해 보세요.

    12. 자주 하는 실수와 해결 방법

    • 함수를 만들었는데 아무 일도 안 일어나요 : 함수를 선언만 하고 호출하지 않은 경우입니다. 함수 이름 뒤에 괄호를 붙여 sayHello();처럼 호출하세요.
    • 괄호 없이 함수 이름만 씀 : console.log(add)처럼 괄호를 빠뜨리면 실행 결과가 아니라 함수 자체의 코드가 출력됩니다.
    • 결과가 undefined로 나와요 : 함수 안에서 return을 쓰지 않고 console.log만 한 경우입니다. 값을 돌려받으려면 return을 사용하세요.
    • return 아래 코드가 실행되지 않아요 : return을 만나면 함수가 즉시 끝나기 때문입니다. 실행할 코드는 return보다 위에 두세요.
    • 화살표 함수가 “before initialization” 오류를 내요 : 화살표 함수를 만들기 전에 호출한 경우입니다. 함수를 먼저 만들고 아래에서 호출하세요.
    • 화살표 함수에서 중괄호를 쓰고 return을 빠뜨림 : (a, b) => { a + b }처럼 중괄호를 쓰면 자동 return이 되지 않아 undefined가 나옵니다. 중괄호를 쓰면 return도 함께 써야 합니다.
    • is not defined 오류 : 함수 안에서 만든 지역 변수를 함수 밖에서 사용하려 한 경우입니다. 필요하다면 return으로 값을 돌려받아 사용하세요.

    마무리하며

    오늘은 코드를 묶어 재사용하는 함수에 대해 알아보았습니다. 함수는 선언만으로는 실행되지 않고 괄호를 붙여 호출해야 하며, 매개변수로 값을 받고 return으로 결과를 돌려준다는 기본 흐름을 꼭 기억해 두세요. 특히 결과를 보여주기만 하는 console.log와 결과를 돌려주는 return의 차이는 처음에 가장 많이 헷갈리는 부분입니다. 화살표 함수는 기본 함수를 짧게 쓰는 문법으로, 선언 전에 호출할 수 없다는 점과 this가 다르게 동작한다는 차이가 있습니다. 앞으로 작성하는 코드에서 비슷한 내용이 반복된다면 “이걸 함수로 만들 수 있지 않을까?”라고 생각해 보는 습관을 들여 보세요.

    지금까지는 결과를 콘솔에서만 확인했지만, 다음 글에서는 드디어 웹페이지의 버튼을 클릭하면 반응하는 기능을 만들어 봅니다. 오늘 배운 함수가 이벤트와 만나 어떻게 살아 움직이는 웹페이지를 만드는지 addEventListener와 함께 알아보겠습니다. 궁금한 점은 댓글로 남겨 주세요!

    댓글 0

    댓글 남기기