함수 선언식·표현식의 차이, 매개변수와 기본값, 반환값, 함수 스코프와 클로저 입문까지 함수의 모든 기초를 실전 예제로 완전히 이해합니다.
🎯 학습 목표
이 강을 마치면 다음을 할 수 있습니다.
- 함수 선언식과 함수 표현식의 차이를 이해하고 상황에 맞게 선택할 수 있습니다.
- 매개변수, 기본값 매개변수, 나머지 매개변수를 올바르게 사용할 수 있습니다.
return으로 함수에서 값을 반환하고 활용할 수 있습니다.- 함수 스코프를 이해하고 변수의 유효 범위를 올바르게 설계할 수 있습니다.
💡 함수란 무엇인가 — 코드의 레시피
이 섹션에서는 함수의 개념과 함수가 왜 프로그래밍의 핵심 도구인지 살펴보겠습니다.
함수(Function)는 특정 작업을 수행하는 코드 블록에 이름을 붙인 것입니다. 마치 요리 레시피와 같습니다. 「김치찌개 만드는 법」이라는 레시피를 한 번 작성해두면, 누구든 그 이름만 부르면 절차를 따를 수 있습니다. 함수도 마찬가지로, 한 번 정의해두면 이름을 불러서 언제든 재사용할 수 있습니다.
함수를 사용하는 이유는 크게 세 가지입니다. 첫째 재사용성입니다. 같은 코드를 여러 곳에서 쓰고 싶을 때 함수로 만들면 한 번만 작성하고 여러 번 호출할 수 있습니다. 둘째 가독성입니다. 복잡한 로직을 의미 있는 이름의 함수로 분리하면, 코드의 의도를 더 명확하게 표현할 수 있습니다. 셋째 유지보수입니다. 버그를 수정하거나 로직을 변경할 때 함수 하나만 수정하면 그 함수를 호출하는 모든 곳에 반영됩니다.
// 함수 없는 코드 — 중복 반복
console.log("안녕하세요, 홍길동님!");
console.log("포인트: 1200점");
console.log("---");
console.log("안녕하세요, 김철수님!");
console.log("포인트: 850점");
console.log("---");
// 함수로 만들어 재사용
function greetUser(name, points) {
console.log(`안녕하세요, ${name}님!`);
console.log(`포인트: ${points}점`);
console.log("---");
}
greetUser("홍길동", 1200);
greetUser("김철수", 850);
greetUser("이영희", 3000); // 새 사용자 추가도 한 줄
📝 함수 선언과 호출
이 섹션에서는 함수를 만드는 두 가지 주요 방법인 함수 선언식과 함수 표현식의 구조와 차이를 살펴보겠습니다.
자바스크립트에서 함수를 만드는 방법은 여러 가지가 있습니다. 가장 기본적인 두 가지를 먼저 살펴보겠습니다.
// 1. 함수 선언식 (Function Declaration)
function add(a, b) {
return a + b;
}
// 선언 전에 호출해도 작동! (호이스팅)
console.log(multiply(3, 4)); // 12 — 선언 전에 호출 가능
function multiply(a, b) {
return a * b;
}
// 2. 함수 표현식 (Function Expression)
// 함수를 변수에 저장
const subtract = function(a, b) {
return a - b;
};
// 선언 전에 호출하면 오류!
// console.log(divide(10, 2)); // ❌ ReferenceError
const divide = function(a, b) {
return a / b;
};
// 호출 방법
console.log(add(3, 5)); // 8
console.log(subtract(10, 4)); // 6
console.log(divide(20, 4)); // 5
함수 선언식과 표현식의 가장 큰 차이는 호이스팅(Hoisting)입니다. 함수 선언식은 자바스크립트 엔진이 코드를 실행하기 전에 함수 정의를 파일 최상단으로 끌어올립니다. 따라서 선언 전에 호출해도 오류가 없습니다. 반면 함수 표현식은 변수에 할당되는 시점에만 사용할 수 있어, 선언 이전에 호출하면 오류가 발생합니다.
어느 방식이 더 좋을까요? 상황에 따라 다릅니다. 일반적인 유틸리티 함수는 선언식, 특정 조건에서만 생성되는 함수나 콜백으로 전달할 함수는 표현식이나 다음 강에서 배울 화살표 함수를 사용합니다. 중요한 것은 코드 전체에서 일관된 방식을 선택하는 것입니다.
📥 매개변수와 반환값
이 섹션에서는 함수에 데이터를 전달하는 매개변수와 함수가 결과를 돌려주는 반환값을 자세히 살펴보겠습니다.
매개변수(Parameter)는 함수를 정의할 때 사용하는 변수로, 외부에서 전달받은 값을 담습니다. 인수(Argument)는 함수를 호출할 때 실제로 전달하는 값입니다. 매개변수는 함수 안에서만 살아있는 지역 변수입니다.
// 기본 매개변수
function greet(name) { // name은 매개변수
console.log(`안녕하세요, ${name}님!`);
}
greet("홍길동"); // "홍길동"은 인수
// 여러 매개변수
function calcBMI(weight, height) {
const bmi = weight / (height * height);
return bmi.toFixed(1); // 소수점 1자리로 반올림
}
console.log(calcBMI(70, 1.75)); // "22.9"
// 기본값 매개변수 (Default Parameter) — ES6
function createGreeting(name, prefix = "안녕하세요") {
return `${prefix}, ${name}님!`;
}
console.log(createGreeting("홍길동")); // "안녕하세요, 홍길동님!"
console.log(createGreeting("홍길동", "반갑습니다")); // "반갑습니다, 홍길동님!"
// 나머지 매개변수 (Rest Parameter) — 가변 인수 처리
function sum(...numbers) { // ...은 "나머지 모두"를 배열로 모음
let total = 0;
for (const num of numbers) {
total += num;
}
return total;
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20, 30, 40)); // 100
기본값 매개변수(Default Parameter)는 인수가 전달되지 않거나 undefined일 때 사용할 기본값을 지정합니다. 옵션 처리를 간결하게 만들어줍니다. 나머지 매개변수(Rest Parameter)는 ...로 표시하며, 지정되지 않은 나머지 모든 인수를 배열로 수집합니다. 개수가 정해지지 않은 인수를 처리할 때 유용합니다.
이제 함수가 결과를 돌려주는 반환값을 살펴보겠습니다.
// return이 있는 함수 — 값을 반환
function square(n) {
return n * n; // 함수 실행을 중단하고 값을 반환
console.log("이 줄은 실행되지 않습니다."); // return 이후 코드는 무시
}
const result = square(5);
console.log(result); // 25
console.log(square(10) + square(3)); // 109 (100 + 9)
// return이 없는 함수 — undefined를 반환
function logMessage(msg) {
console.log(msg);
// return 없음
}
const value = logMessage("안녕"); // 안녕 출력
console.log(value); // undefined
// 여러 값 반환 — 객체로 묶어서
function minMax(numbers) {
const min = Math.min(...numbers);
const max = Math.max(...numbers);
return { min, max }; // 객체로 반환 (14강에서 자세히)
}
const stats = minMax([3, 1, 7, 2, 9, 4]);
console.log(stats.min); // 1
console.log(stats.max); // 9
return문은 두 가지 역할을 합니다. 첫째, 함수 실행을 즉시 종료합니다. 둘째, 호출한 곳으로 값을 돌려줍니다. return 이후의 코드는 절대 실행되지 않습니다. 함수는 오직 하나의 값만 반환할 수 있습니다. 여러 값이 필요하면 객체나 배열로 묶어서 반환합니다.
🔭 함수 스코프와 클로저 입문
이 섹션에서는 함수 안에서의 변수 유효 범위(함수 스코프)와 클로저의 기초 개념을 살펴보겠습니다.
3강에서 블록 스코프를 배웠습니다. 함수도 스코프를 만듭니다. 함수 안에서 선언된 변수는 함수 밖에서 접근할 수 없습니다. 이것이 함수 스코프(Function Scope)입니다.
// 함수 스코프
let globalMessage = "전역 변수";
function showScope() {
let localMessage = "지역 변수"; // 함수 안에서만 존재
console.log(globalMessage); // ✅ 전역 변수 접근 가능
console.log(localMessage); // ✅ 지역 변수 접근 가능
}
showScope();
console.log(globalMessage); // ✅ 전역 변수 접근 가능
// console.log(localMessage); // ❌ ReferenceError — 함수 밖 접근 불가
// 같은 이름이라도 함수 안팎은 별개의 변수
let count = 10; // 전역 count
function resetCount() {
let count = 0; // 지역 count — 전역 count와 별개
console.log(count); // 0
}
resetCount();
console.log(count); // 10 — 전역 count는 변하지 않음
함수 스코프 덕분에 함수 안에서 만든 변수들은 외부 코드에 영향을 주지 않습니다. 함수가 자체적인 "작업 공간"을 갖는 것과 같습니다. 이것이 함수로 코드를 분리하는 것이 안전한 이유 중 하나입니다.
조금 더 깊이 들어가면 클로저(Closure)라는 개념이 있습니다. 클로저는 함수가 자신이 생성될 때의 환경(스코프)을 기억하는 특성입니다.
// 클로저 기초 예시
function makeCounter() {
let count = 0; // makeCounter 스코프의 변수
function increment() {
count++; // 바깥 함수의 count에 접근
return count;
}
return increment; // 함수를 반환
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// count는 counter 함수가 기억하고 있음 — 클로저!
makeCounter()가 실행이 끝난 후에도, 반환된 increment 함수는 count 변수를 기억합니다. counter()를 호출할 때마다 같은 count 변수가 증가합니다. 이것이 클로저입니다. 클로저는 자바스크립트에서 매우 중요한 개념으로, 24강 비동기와 25강 async/await에서 더 깊이 활용됩니다. 지금은 "함수가 자신이 태어난 환경을 기억한다"는 것만 이해하면 충분합니다.
⚠️ 자주 하는 실수와 주의점
이 섹션에서는 함수 사용 시 입문자들이 자주 겪는 실수를 살펴보겠습니다.
함수 호출 시 괄호를 빠뜨리는 실수가 가장 흔합니다. greet는 함수 자체를 값으로 참조하는 것이고, greet()는 함수를 실행하는 것입니다. 콘솔에 console.log(greet)를 출력하면 함수의 소스코드가 출력되고, console.log(greet())는 함수 실행 결과가 출력됩니다. 이 차이는 이벤트 처리(18강)에서 매우 중요해집니다.
function greet() {
return "안녕하세요!";
}
console.log(greet); // ƒ greet() { return "안녕하세요!"; } — 함수 자체
console.log(greet()); // "안녕하세요!" — 함수 실행 결과
return 값을 사용하지 않는 실수도 자주 발생합니다. 함수가 값을 반환해도 그 값을 변수에 저장하거나 사용하지 않으면 의미가 없습니다. 계산 결과가 필요하면 반드시 반환값을 받아서 사용해야 합니다.
매개변수 개수 불일치도 주의해야 합니다. 자바스크립트는 인수를 적게 전달해도 오류를 내지 않습니다. 전달받지 못한 매개변수는 undefined가 됩니다. 이 경우 예상치 못한 NaN이나 오류로 이어질 수 있으므로, 기본값 매개변수를 활용하거나 함수 안에서 유효성 검사를 하는 것이 좋습니다.
📝 핵심 요약
9강에서 배운 내용을 정리해 보겠습니다.
| 항목 | 설명 | 예시 |
|---|---|---|
| 함수 선언식 | 호이스팅 O, 선언 전 호출 가능 | function add(a, b) { ... } |
| 함수 표현식 | 호이스팅 X, 선언 후 호출 가능 | const add = function(a, b) { ... } |
| 매개변수 | 함수 정의 시 입력 변수 | function f(name) { } |
| 인수 | 함수 호출 시 전달 값 | f("홍길동") |
| 기본값 매개변수 | 인수 없을 때 사용할 기본값 | function f(name = "손님") |
| 나머지 매개변수 | 가변 인수를 배열로 수집 | function f(...args) |
| return | 함수 종료 + 값 반환 | return a + b; |
| 함수 스코프 | 함수 안 변수는 밖에서 접근 불가 | 지역 변수의 유효 범위 |
다음 강인 10강 — 화살표 함수에서는 ES6에서 도입된 현대적인 함수 표기법인 화살표 함수를 배웁니다. 일반 함수와의 차이, 특히 this 바인딩 차이를 이해하면 실무 코드를 읽고 쓰는 능력이 크게 향상됩니다!
관련 주제
- 함수 선언식
- 함수 표현식
- 매개변수 기본값
- 나머지 매개변수
- return 반환값
- 함수 스코프
- 클로저 입문
- 개발·프로그래밍
- 개발·프로그래밍 강의
- 자바스크립트 기초 30강 — 웹을 움직이는 언어
- 무료강의
- 무료 온라인 강의
- NUGUNA
- 누구나
📚 시리즈 전체 공유
자바스크립트 기초 30강 — 웹을 움직이는 언어
이 강의가 속한 시리즈는 총 22강, 모두 무료입니다. 처음부터 배우려는 동료에게 시리즈 전체를 알려 주세요.
댓글
불러오는 중...
