함수란?
함수는 특정 작업을 수행하는 코드의 집합입니다. 한 번 정의하면 여러 번 재사용할 수 있어 코드의 중복을 줄이고 유지보수를 쉽게 만듭니다. JavaScript에서 함수를 만드는 방법은 크게 함수 선언식과 함수 표현식 두 가지가 있습니다.
함수 선언식 (Function Declaration)
함수 선언식은 function
키워드로 시작하여 함수를 정의하는 가장 기본적인 방법입니다. 함수 이름을 반드시 지정해야 하며, 코드 어디서든 호출할 수 있습니다.
함수 선언식 문법
// 문법
function 함수이름(매개변수) {
실행문....
return 반환값; // 선택사항
}
// 사용법
function greet(name) {
return "안녕하세요, " + name + "님!";
}
함수 선언식 기본 예제
// 함수 정의
function sayHello() {
console.log("안녕하세요!");
}
// 함수 호출
sayHello(); // "안녕하세요!" 출력
// 매개변수가 있는 함수
function add(a, b) {
return a + b;
}
let result = add(5, 3);
console.log(result); // 8 출력
실행 결과:
안녕하세요!
8
함수 선언식으로 정의된 sayHello
함수와 add
함수는 정의된 후 언제든지 호출할 수 있습니다. add
함수는 두 매개변수를 받아 더한 값을 반환합니다.
함수 선언식의 호이스팅
// 함수 정의 전에 호출 가능 (호이스팅)
console.log(multiply(4, 5)); // 20 출력
function multiply(x, y) {
return x * y;
}
console.log(multiply(2, 3)); // 6 출력
실행 결과:
20
6
함수 선언식은 호이스팅에 의해 함수가 정의되기 전에도 호출할 수 있습니다. JavaScript 엔진이 코드를 실행하기 전에 함수 선언을 먼저 처리하기 때문입니다.
함수 표현식 (Function Expression)
함수 표현식은 변수에 함수를 할당하는 방식으로 함수를 정의하는 방법입니다. 함수 이름을 생략할 수 있으며(익명 함수), 변수가 선언된 이후에만 호출할 수 있습니다.
함수 표현식 문법
// 문법
let 변수이름 = function(매개변수) {
실행문....
return 반환값; // 선택사항
};
// 사용법
let greet = function(name) {
return "안녕하세요, " + name + "님!";
};
함수 표현식 기본 예제
// 익명 함수 표현식
let sayGoodbye = function() {
console.log("안녕히 가세요!");
};
// 함수 호출
sayGoodbye(); // "안녕히 가세요!" 출력
// 매개변수가 있는 함수 표현식
let subtract = function(a, b) {
return a - b;
};
let result = subtract(10, 4);
console.log(result); // 6 출력
실행 결과:
안녕히 가세요!
6
함수 표현식으로 정의된 함수는 변수에 저장되므로, 일반 변수처럼 다른 함수의 매개변수로 전달하거나 다른 변수에 할당할 수 있습니다.
기명 함수 표현식
// 함수 이름을 지정한 함수 표현식
let factorial = function fact(n) {
if (n <= 1) {
return 1;
}
return n * fact(n - 1); // 함수 내부에서 자기 자신 호출
};
console.log(factorial(5)); // 120 출력
실행 결과:
120
기명 함수 표현식은 함수 내부에서 자기 자신을 참조할 때 유용합니다. 재귀 함수를 만들 때 주로 사용됩니다.
호이스팅의 차이점
함수 선언식과 표현식의 가장 큰 차이점은 호이스팅 동작입니다.
함수 선언식의 호이스팅
// 함수 정의 전에 호출 가능
console.log(declaration()); // "함수 선언식입니다!" 출력
function declaration() {
return "함수 선언식입니다!";
}
함수 표현식의 호이스팅
// 변수 선언 전에 호출 - 에러 발생
console.log(expression()); // TypeError: expression is not a function
var expression = function() {
return "함수 표현식입니다!";
};
let/const 사용 시 함수 표현식
// let/const 사용 시 - ReferenceError 발생
console.log(modernExpression()); // ReferenceError: Cannot access 'modernExpression' before initialization
let modernExpression = function() {
return "모던 함수 표현식입니다!";
};
호이스팅 동작 원리:
// 실제 코드
console.log(func1()); // 작동함
console.log(func2()); // 에러 발생
function func1() {
return "선언식";
}
var func2 = function() {
return "표현식";
};
// JavaScript 엔진이 해석하는 방식
function func1() {
return "선언식";
}
var func2; // undefined로 초기화
console.log(func1()); // "선언식" 출력
console.log(func2()); // TypeError: func2 is not a function
func2 = function() {
return "표현식";
};
선언식 vs 표현식 비교
📊 비교표
특징 | 함수 선언식 | 함수 표현식 |
---|---|---|
문법 | function 이름() {} |
let 이름 = function() {} |
호이스팅 | 완전히 호이스팅됨 | 변수만 호이스팅됨 |
호출 시점 | 어디서든 호출 가능 | 정의 이후에만 호출 가능 |
함수 이름 | 필수 | 선택 (익명 가능) |
블록 스코프 | 함수 스코프 | 변수 선언 방식에 따름 |
🔍 상세 비교 예제
// 1. 호출 시점 테스트
console.log("=== 호출 시점 테스트 ===");
// 선언식 - 정의 전 호출 가능
console.log(declarationTest()); // "선언식 함수" 출력
// 표현식 - 정의 전 호출 불가능
try {
console.log(expressionTest()); // 에러 발생
} catch (error) {
console.log("표현식 함수 호출 에러:", error.message);
}
function declarationTest() {
return "선언식 함수";
}
let expressionTest = function() {
return "표현식 함수";
};
// 정의 후 호출
console.log(expressionTest()); // "표현식 함수" 출력
실행 결과:
=== 호출 시점 테스트 ===
선언식 함수
표현식 함수 호출 에러: expressionTest is not a function
표현식 함수
// 2. 조건부 함수 정의
console.log("=== 조건부 함수 정의 ===");
let condition = true;
if (condition) {
// 함수 선언식 (권장하지 않음)
function conditionalDeclaration() {
return "조건부 선언식";
}
// 함수 표현식 (권장)
var conditionalExpression = function() {
return "조건부 표현식";
};
}
// 브라우저마다 다른 결과가 나올 수 있음
try {
console.log(conditionalDeclaration());
} catch (error) {
console.log("조건부 선언식 에러");
}
try {
console.log(conditionalExpression());
} catch (error) {
console.log("조건부 표현식 에러");
}
언제 어떤 것을 사용할까?
🎯 함수 선언식을 사용하는 경우
// 1. 메인 로직 함수들
function calculateTax(price, rate) {
return price * rate;
}
function formatCurrency(amount) {
return new Intl.NumberFormat('ko-KR', {
style: 'currency',
currency: 'KRW'
}).format(amount);
}
// 2. 유틸리티 함수들
function isValidEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function getRandomNumber(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// 3. 재귀 함수
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 함수들을 어디서든 사용 가능
let price = 1000;
let tax = calculateTax(price, 0.1);
console.log(formatCurrency(price + tax)); // ₩1,100
🎯 함수 표현식을 사용하는 경우
// 1. 조건부 함수 정의
let calculator = {};
let operation = "add";
if (operation === "add") {
calculator.operate = function(a, b) {
return a + b;
};
} else if (operation === "multiply") {
calculator.operate = function(a, b) {
return a * b;
};
}
// 2. 콜백 함수
let numbers = [1, 2, 3, 4, 5];
let doubled = numbers.map(function(num) {
return num * 2;
});
let filtered = numbers.filter(function(num) {
return num > 3;
});
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(filtered); // [4, 5]
// 3. 즉시 실행 함수 표현식 (IIFE)
let result = (function() {
let privateVar = "비공개 변수";
return {
getPrivateVar: function() {
return privateVar;
}
};
})();
console.log(result.getPrivateVar()); // "비공개 변수"
// 4. 이벤트 핸들러 (웹 환경)
let button = document.getElementById('myButton');
if (button) {
button.addEventListener('click', function() {
console.log('버튼이 클릭되었습니다!');
});
}
🔧 ES6 화살표 함수와의 비교
// 함수 표현식
let traditionalFunction = function(x, y) {
return x + y;
};
// 화살표 함수 (ES6)
let arrowFunction = (x, y) => {
return x + y;
};
// 화살표 함수 (간단한 형태)
let simpleArrow = (x, y) => x + y;
// 모두 같은 결과
console.log(traditionalFunction(3, 4)); // 7
console.log(arrowFunction(3, 4)); // 7
console.log(simpleArrow(3, 4)); // 7
// this 바인딩의 차이
let obj = {
name: "객체",
traditionalMethod: function() {
console.log("전통적 함수:", this.name); // "객체"
},
arrowMethod: () => {
console.log("화살표 함수:", this.name); // undefined (전역 this)
}
};
obj.traditionalMethod(); // "전통적 함수: 객체"
obj.arrowMethod(); // "화살표 함수: undefined"
실무 권장사항
📋 권장 사용 패턴
// ✅ 권장: 주요 비즈니스 로직은 함수 선언식
function processOrder(order) {
validateOrder(order);
calculateTotal(order);
saveOrder(order);
sendConfirmation(order);
}
function validateOrder(order) {
if (!order.items || order.items.length === 0) {
throw new Error("주문 항목이 없습니다.");
}
}
// ✅ 권장: 조건부 로직은 함수 표현식
let paymentProcessor;
if (config.paymentMethod === 'card') {
paymentProcessor = function(amount) {
return processCardPayment(amount);
};
} else {
paymentProcessor = function(amount) {
return processBankTransfer(amount);
};
}
// ✅ 권장: 콜백과 고차 함수는 화살표 함수
const users = [
{ name: "김철수", age: 25 },
{ name: "이영희", age: 30 },
{ name: "박민수", age: 35 }
];
const adults = users
.filter(user => user.age >= 18)
.map(user => user.name)
.sort();
console.log(adults); // ["김철수", "이영희", "박민수"]
⚠️ 피해야 할 패턴
// ❌ 피하기: 조건문 내부의 함수 선언식
if (someCondition) {
function badFunction() {
return "이렇게 하지 마세요";
}
}
// ✅ 개선: 함수 표현식 사용
let goodFunction;
if (someCondition) {
goodFunction = function() {
return "이렇게 하세요";
};
}
// ❌ 피하기: 반복문 내부의 함수 선언식
for (let i = 0; i < 3; i++) {
function badLoop() {
console.log(i);
}
}
// ✅ 개선: 함수 표현식 사용
for (let i = 0; i < 3; i++) {
let goodLoop = function() {
console.log(i);
};
}
마무리
JavaScript에서 함수를 정의하는 두 가지 주요 방법인 함수 선언식과 함수 표현식을 알아보았습니다.
✅ 핵심 정리
- 함수 선언식: 호이스팅되어 어디서든 호출 가능, 주요 로직에 적합
- 함수 표현식: 정의 후에만 호출 가능, 조건부 로직이나 콜백에 적합
- 호이스팅 차이: 선언식은 완전히 호이스팅, 표현식은 변수만 호이스팅
- 사용 목적: 안정적인 메인 로직은 선언식, 동적인 로직은 표현식
두 방식의 특성을 이해하고 상황에 맞게 선택하면 더 안정적이고 읽기 쉬운 코드를 작성할 수 있습니다!
'JavaScript > 함수 완전 정복' 카테고리의 다른 글
JavaScript 콜백 함수 개념 이해 - 간단 가이드 (0) | 2025.06.24 |
---|---|
JavaScript 화살표 함수 (Arrow Function) 완전 가이드 (3) | 2025.06.07 |
JavaScript 함수의 매개변수와 반환값 완전 가이드 (3) | 2025.06.06 |