함수 선언식
JavaScript에서 function 키워드를 사용하여 이름이 있는 함수를 선언하는 방식으로, 호이스팅에 의해 선언 전에도 호출할 수 있는 특징을 가집니다.
함수 선언식 vs 함수 표현식
| 항목 | 함수 선언식 (Declaration) | 함수 표현식 (Expression) |
|---|---|---|
| 문법 | function 이름() {} | const 이름 = function() {} |
| 호이스팅 | 전체가 호이스팅됨 (선언 전 호출 가능) | 변수만 호이스팅 (선언 전 호출 불가) |
| 이름 | 필수 | 선택 (익명 함수 가능) |
| 세미콜론 | 필요 없음 | 필요 (문장이므로) |
// 함수 선언식 (Function Declaration)
function add(a, b) {
return a + b;
}
// 함수 표현식 (Function Expression)
const add = function(a, b) {
return a + b;
};
// 화살표 함수 (Arrow Function — 함수 표현식의 한 형태)
const add = (a, b) => a + b;
호이스팅 차이
이것이 함수 선언식과 함수 표현식의 가장 중요한 차이입니다.
// O 함수 선언식 — 선언 전에 호출 가능
console.log(add(1, 2)); // 3 (정상 동작)
function add(a, b) {
return a + b;
}
// X 함수 표현식 — 선언 전에 호출 불가
console.log(add(1, 2)); // ReferenceError: Cannot access 'add'
const add = function(a, b) {
return a + b;
};
// X 화살표 함수 — 함수 표현식이므로 동일하게 불가
console.log(add(1, 2)); // ReferenceError
const add = (a, b) => a + b;
호이스팅 동작 원리
JavaScript 엔진이 코드를 실행하기 전에 먼저 선언을 끌어올림
[함수 선언식 — 전체가 호이스팅]
// 실제 코드 // 엔진이 해석하는 순서
greet("홍길동"); function greet(name) {
return `안녕 ${name}`;
function greet(name) { }
return `안녕 ${name}`; greet("홍길동"); // O 정상
}
[함수 표현식 — 변수 선언만 호이스팅, 할당은 그 자리]
// 실제 코드 // 엔진이 해석하는 순서
greet("홍길동"); let greet; // 선언만 호이스팅 (TDZ)
greet("홍길동"); // X 에러
const greet = function(name) {
return `안녕 ${name}`; greet = function(name) {
}; return `안녕 ${name}`;
};
함수 정의 방식 전체 비교
// 1. 함수 선언식 (Function Declaration)
function add(a, b) {
return a + b;
}
// 2. 함수 표현식 (Function Expression)
const add = function(a, b) {
return a + b;
};
// 3. 기명 함수 표현식 (Named Function Expression)
const add = function addFn(a, b) {
return a + b;
};
// addFn은 함수 내부에서만 접근 가능 (재귀 등에 사용)
// 4. 화살표 함수 (Arrow Function)
const add = (a, b) => a + b;
// 5. 즉시 실행 함수 (IIFE)
(function() {
console.log("즉시 실행");
})();
| 방식 | 호이스팅 | this 바인딩 | arguments 객체 | 생성자 사용 |
|---|---|---|---|---|
| 함수 선언식 | O 전체 | 동적 (호출 방식에 따라) | O | O new 가능 |
| 함수 표현식 | X 변수만 | 동적 (호출 방식에 따라) | O | O new 가능 |
| 화살표 함수 | X 변수만 | 정적 (상위 스코프 고정) | X | X new 불가 |
this 바인딩 차이
const obj = {
name: "홍길동",
// 함수 선언식/표현식 — this가 호출 객체를 가리킴
greet: function() {
console.log(this.name); // "홍길동" (this = obj)
// 내부 함수에서 this 문제
setTimeout(function() {
console.log(this.name); // undefined (this = window)
}, 100);
},
// 화살표 함수 — this가 선언 시점의 상위 스코프 고정
greetArrow: function() {
console.log(this.name); // "홍길동"
setTimeout(() => {
console.log(this.name); // "홍길동" (상위 this 유지)
}, 100);
}
};
함수 선언식의 주의점
조건문 안의 함수 선언식
// 비엄격 모드에서 브라우저마다 동작이 다를 수 있음
if (true) {
function greet() {
return "hello";
}
}
greet(); // 브라우저마다 결과가 다를 수 있음
// O 함수 표현식으로 사용하는 것이 안전
let greet;
if (true) {
greet = function() {
return "hello";
};
}
greet(); // "hello" (예측 가능)
같은 이름 함수 선언식 중복
function add(a, b) {
return a + b;
}
function add(a, b) {
return a * b; // 나중 선언이 덮어씀
}
add(2, 3); // 6 (곱셈으로 덮어써짐, 에러 없음)
// const 함수 표현식은 중복 시 에러 발생
const add = (a, b) => a + b;
const add = (a, b) => a * b; // X SyntaxError: Identifier already declared
실무 사용 가이드
일반적인 권장 사항:
① 최상위 레벨의 유틸 함수 → 함수 선언식
- 호이스팅 덕분에 코드 순서에 자유로움
- 파일 하단에 선언하고 상단에서 호출 가능
② 콜백, 변수 할당, 모듈 export → 함수 표현식 / 화살표 함수
- 호출 순서가 명확, 재할당 방지 (const)
- 화살표 함수는 this가 고정되어 콜백에 적합
③ 메서드 정의 → 함수 표현식 또는 축약 문법
- 객체/클래스의 메서드에 적합
// ① 유틸 함수 — 함수 선언식
function formatDate(date) {
return date.toISOString().split("T")[0];
}
// ② 콜백 — 화살표 함수
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
// ② 모듈 export — 화살표 함수 또는 함수 표현식
export const fetchUser = async (id) => {
const response = await fetch(`/api/users/${id}`);
return response.json();
};
// ③ 클래스 메서드 — 축약 문법
class UserService {
findById(id) {
return this.repository.find(id);
}
}