함수 선언문 vs 표현식 vs 화살표 함수 — 언제 뭘 쓰나
자바스크립트에서 함수를 만드는 방법이 세 가지나 되다 보니, 면접에서 "차이점이 뭔가요?"라는 질문이 정말 자주 나옵니다. 핵심은 **호이스팅 **, **this 바인딩 **, arguments 객체 세 가지입니다.
세 가지 함수 정의 방식
// 1. 함수 선언문 (Function Declaration)
function greet(name) {
return `안녕, ${name}!`;
}
// 2. 함수 표현식 (Function Expression)
const greet2 = function (name) {
return `안녕, ${name}!`;
};
// 3. 화살표 함수 (Arrow Function)
const greet3 = (name) => `안녕, ${name}!`;
호이스팅 차이
함수 선언문만 호이스팅됩니다. 이것이 첫 번째 핵심 차이입니다.
// 함수 선언문 — 선언 전에 호출 가능
sayHello(); // "hello" ← 정상 동작
function sayHello() {
console.log("hello");
}
// 함수 표현식 — 선언 전에 호출 불가
sayBye(); // ReferenceError (let) 또는 TypeError (var)
const sayBye = function () {
console.log("bye");
};
// 화살표 함수 — 함수 표현식과 동일
sayHi(); // ReferenceError
const sayHi = () => console.log("hi");
면접에서 "함수 표현식은 호이스팅되나요?"라고 물어보면, 변수 선언 자체는 호이스팅되지만 ** 할당은 호이스팅되지 않는다 **고 답하면 됩니다.
this 바인딩 — 가장 중요한 차이
const user = {
name: "정훈",
// 일반 함수: this는 호출한 객체
greet() {
console.log(`안녕, ${this.name}`);
},
// 화살표 함수: this는 상위 스코프의 this
greetArrow: () => {
console.log(`안녕, ${this.name}`); // this는 user가 아님!
},
};
user.greet(); // "안녕, 정훈"
user.greetArrow(); // "안녕, undefined" — this가 전역 객체를 가리킴
화살표 함수는 자신만의 this를 갖지 않고 ** 렉시컬 스코프의 this**를 사용합니다. 이 특성 때문에 객체의 메서드로는 화살표 함수를 쓰면 안 됩니다.
화살표 함수가 유리한 경우
const timer = {
seconds: 0,
start() {
// 화살표 함수가 적합한 경우: 콜백에서 외부 this 유지
setInterval(() => {
this.seconds++; // this가 timer를 가리킴
console.log(this.seconds);
}, 1000);
},
};
// 만약 일반 함수를 쓰면 this가 window를 가리킴
const timerBroken = {
seconds: 0,
start() {
setInterval(function () {
this.seconds++; // this === window — 의도와 다름
}, 1000);
},
};
arguments 객체
// 일반 함수: arguments 사용 가능
function sum() {
return [...arguments].reduce((a, b) => a + b, 0);
}
console.log(sum(1, 2, 3)); // 6
// 화살표 함수: arguments 없음
const sumArrow = () => {
console.log(arguments); // ReferenceError
};
// 대신 rest 파라미터를 사용
const sumRest = (...args) => args.reduce((a, b) => a + b, 0);
console.log(sumRest(1, 2, 3)); // 6
new 키워드 사용 가능 여부
// 함수 선언문/표현식: 생성자로 사용 가능
function Person(name) {
this.name = name;
}
const p = new Person("정훈"); // OK
// 화살표 함수: 생성자로 사용 불가
const PersonArrow = (name) => {
this.name = name;
};
const p2 = new PersonArrow("정훈"); // TypeError: not a constructor
화살표 함수는 prototype 프로퍼티가 없어서 new와 함께 사용할 수 없습니다.
화살표 함수의 간결한 문법
// 매개변수가 하나면 괄호 생략 가능
const double = x => x * 2;
// 객체 리터럴 반환 시 소괄호로 감싸기
const makeUser = (name) => ({ name, createdAt: Date.now() });
// 본문이 여러 줄이면 중괄호 + return 필요
const calculate = (a, b) => {
const sum = a + b;
const avg = sum / 2;
return avg;
};
상황별 선택 가이드
| 상황 | 추천 방식 | 이유 |
|---|---|---|
| 일반 유틸 함수 | 함수 선언문 | 호이스팅으로 코드 순서 자유로움 |
| 콜백 함수 | 화살표 함수 | 간결하고 this 문제 없음 |
| 객체 메서드 | 메서드 축약 (greet() {}) | this가 객체를 가리킴 |
| 생성자 | 함수 선언문 (or class) | 화살표 함수는 생성자 불가 |
| 이벤트 핸들러 | 일반 함수 | this가 이벤트 대상 요소 |
| React 컴포넌트 | 화살표 함수 (컨벤션) | 팀 컨벤션에 따름 |
정리
함수 선언문: 호이스팅 O | 자체 this O | arguments O | new O
함수 표현식: 호이스팅 X | 자체 this O | arguments O | new O
화살표 함수: 호이스팅 X | 자체 this X | arguments X | new X
**기억하기 **: "화살표 함수는 가볍지만 this, arguments, new가 없다." 이 한 문장을 기억하면 면접에서 당황하지 않습니다. 콜백에는 화살표, 메서드에는 일반 함수가 안전한 선택입니다.
댓글 로딩 중...