🟨 1-6. 함수 선언문 vs 함수 표현식 — 호출 타이밍과 작동 원리 완벽 이해
“자바스크립트 함수의 진짜 차이를 모르면, 코드가 왜 에러 나는지 절대 알 수 없다.”
🚀 들어가며
프로그래밍에서 함수는 단순히 코드를 묶는 도구가 아니다.
“재사용성과 구조의 출발점” 이며, 자바스크립트에서는 특히 함수가 일급 객체(First-class Object) 로 취급된다.
그런데 막상 코드를 짜다 보면 이런 혼란에 자주 빠진다.
sayHello(); // ✅ 작동됨
greet(); // ❌ ReferenceError
function sayHello() {
console.log("안녕하세요!");
}
const greet = function() {
console.log("반가워요!");
};
둘 다 “함수 선언” 같아 보이는데, 왜 하나만 실행될까?
이것이 바로 함수 선언문(Function Declaration) 과
함수 표현식(Function Expression) 의 근본적인 차이다.
🧠 함수의 두 가지 선언 방식
1️⃣ 함수 선언문 (Function Declaration)
function sayHello() {
console.log("Hello World!");
}
✅ function 키워드로 시작하며, 이름이 반드시 있다.
✅ 코드 실행 전에 호이스팅(hoisting) 되어 어디서든 호출 가능하다.
즉, 아래처럼 작성해도 동작한다.
sayHello(); // ✅ 정상 실행
function sayHello() {
console.log("Hello World!");
}
💡 이유는, 자바스크립트 엔진이 실행 전에 함수 선언문을 메모리에 먼저 등록하기 때문이다.
2️⃣ 함수 표현식 (Function Expression)
const greet = function() {
console.log("Hi!");
};
✅ 변수에 함수를 값으로 대입하는 형태
✅ “표현식(Expression)”이므로 실행 시점에 할당된다.
✅ 호이스팅 시점에서는 존재하지 않는다.
greet(); // ❌ ReferenceError
const greet = function() {
console.log("Hi!");
};
즉, 함수 표현식은 선언 전에 호출할 수 없다.
함수가 변수에 “대입되는 시점”이 실제로 메모리에 등록되는 시점이기 때문이다.
⚙️ 선언문 vs 표현식 차이 한눈에 비교
구분 함수 선언문 함수 표현식
| 선언 방식 | function 함수명() | const 변수 = function() |
| 이름 존재 | 반드시 있음 | 익명 or 이름 있음 |
| 호이스팅 | 전체 함수가 호이스팅 | 변수만 호이스팅 (값은 undefined) |
| 호출 시점 | 선언 전/후 모두 가능 | 선언 후에만 가능 |
| 사용 예 | 일반적인 유틸 함수, 전역 함수 | 콜백, 즉시 실행, 클로저 등 |
🧩 즉시 실행 함수 (IIFE, Immediately Invoked Function Expression)
함수 표현식은 선언하자마자 바로 실행시킬 수도 있다.
(function() {
console.log("즉시 실행!");
})();
✅ 괄호로 감싸면 “표현식”으로 인식된다.
✅ 뒤에 ()를 붙여 즉시 실행 가능
✅ 전역 스코프 오염 방지에 유용
💬 과거에는 모듈화를 위해 IIFE가 자주 쓰였지만,
지금은 ES6의 모듈(import/export) 이 그 역할을 대체한다.
🧱 이름이 있는 함수 표현식 (Named Function Expression)
const print = function show() {
console.log("출력!");
};
✅ 내부에서는 show() 이름으로 자기 자신 호출 가능
✅ 외부에서는 print()로만 접근 가능
✅ 디버깅 시 함수 이름이 표시되어 에러 추적에 유리
💡 일반 익명 함수보다 디버깅 효율이 좋기 때문에
React 등 일부 프레임워크에서도 이런 형태가 자주 등장한다.
🧮 실무에서 가장 많이 쓰는 패턴
1️⃣ 콜백(callback) 함수로 전달되는 함수 표현식
setTimeout(function() {
console.log("3초 후 실행!");
}, 3000);
✅ 익명 함수 표현식은 콜백 패턴에서 거의 항상 사용된다.
✅ 선언문은 이런 위치에서는 쓸 수 없다.
2️⃣ 배열/객체 메서드 내부에서의 익명 함수
const arr = [1, 2, 3];
arr.forEach(function(num) {
console.log(num);
});
혹은 ES6 이후엔 화살표 함수로 더 간결하게 👇
arr.forEach(num => console.log(num));
✅ 함수 표현식은 변수처럼 인라인 형태로 전달할 때 가장 효율적이다.
🧠 호이스팅 구조 시각화
함수 선언문
say(); // ✅ 실행 가능
function say() {
console.log("Hello");
}
➡️ 메모리 등록 순서
1️⃣ 함수 전체가 먼저 호이스팅
2️⃣ 이후 코드 실행
함수 표현식
say(); // ❌ ReferenceError
const say = function() {
console.log("Hi");
};
➡️ 메모리 등록 순서
1️⃣ 변수 say만 호이스팅됨 (값은 undefined)
2️⃣ 함수는 런타임에 대입되어야 활성화
⚡ 화살표 함수(Arrow Function)까지 함께 이해하기
ES6 이후 함수 표현식은 더 간결한 형태의 화살표 함수로 진화했다.
const greet = () => console.log("Hello!");
구분 전통 함수 화살표 함수
| 키워드 | function | => |
| this 바인딩 | 동적 | 정적 (부모 스코프 유지) |
| 간결성 | 길다 | 짧고 깔끔 |
| return 필요 | 명시적 | 한 줄이면 자동 반환 |
💬 화살표 함수는 this가 고정되어 콜백 함수에서 자주 쓰인다.
다음 편에서 다룰 예정인 스코프(Scope) 와 연관된다.
🎯 전문가 관점에서의 정리
상황 추천 방식 이유
| 전역 유틸 함수 | 선언문 | 어디서든 호출 가능 |
| 콜백, 이벤트 핸들러 | 함수 표현식 / 화살표 함수 | 익명형으로 깔끔하게 전달 |
| 모듈 내부 함수 | const + 화살표 | 스코프 안정성 확보 |
| 즉시 실행 | IIFE | 초기화 코드 실행 시 유용 |
✅ “선언문은 위로 끌어올려 쓰고, 표현식은 흐름 속에서 정의한다.”
코드의 의도와 시점을 명확히 구분하자.
🏁 마무리 — “함수는 코드의 단위, 선언 방식은 흐름의 언어다”
자바스크립트는 함수 중심의 언어다.
하지만 “어디서, 언제, 어떻게 선언했는가” 에 따라
그 함수의 운명은 완전히 달라진다.
- 선언문: 코드 구조 중심
- 표현식: 실행 흐름 중심
💬 “함수의 차이를 아는 순간, 자바스크립트의 실행 구조가 보인다.”
다음 편에서는
✅ 1-7. 스코프(Scope)와 호이스팅(Hoisting) — 변수와 함수의 생명 주기 이해하기
를 통해 자바스크립트가 코드를 읽는 진짜 순서를 시각적으로 풀어보자.