화살표 함수(Arrow Function) vs 일반 함수

자바스크립트 ES6(2015)에서 등장한 화살표 함수는 현대 자바스크립트 개발에서 빼놓을 수 없는 도구가 되었습니다. 하지만 화살표 함수가 단순히 일반 함수의 '축약형'이라고 생각한다면 예상치 못한 버그를 마주할 수 있습니다.
오늘은 이 두 함수의 결정적인 차이점을 예제와 함께 자세히 살펴보겠습니다.
1. 문법적 차이 (Syntax)
가장 먼저 눈에 띄는 것은 생김새입니다. 화살표 함수는 훨씬 간결한 문법을 제공합니다.
일반 함수
function add(a, b) {
return a + b;
}
화살표 함수
const add = (a, b) => a + b; // 중괄호와 return 생략 가능 (한 줄일 때)
매개변수가 하나라면 괄호를 생략할 수 있고, 실행 코드가 한 줄이라면 중괄호와 return 키워드까지 생략할 수 있어 가독성이 뛰어납니다.
2. 가장 결정적인 차이: 'this' 바인딩
두 함수의 가장 큰 차이점은 this를 어떻게 다루느냐에 있습니다.
일반 함수: 호출 방식에 따라 동적으로 결정
일반 함수 내부의 this는 함수를 호출한 객체를 가리킵니다. 이를 '동적 바인딩'이라고 합니다.
const user = {
name: "나개발",
greet: function() {
console.log(`안녕하세요, 제 이름은 ${this.name}입니다.`);
}
};
user.greet(); // 안녕하세요, 제 이름은 나개발입니다.
const standaloneGreet = user.greet;
standaloneGreet(); // 안녕하세요, 제 이름은 undefined입니다. (전역 객체의 name을 찾으려 함)
화살표 함수: 상위 스코프에 따라 결정
화살표 함수는 자신만의 this를 가지지 않습니다. 대신 함수가 선언된 위치의 상위 스코프에 있는 this를 그대로 물려받습니다. 이를 '렉시컬(Lexical) 바인딩'이라고 합니다.
const timer = {
seconds: 0,
start: function() {
// 여기서 this는 timer 객체
setInterval(() => {
// 화살표 함수이므로 상위 스코프인 start의 this(timer)를 사용함
this.seconds++;
console.log(this.seconds);
}, 1000);
}
};
timer.start(); // 1, 2, 3... 정상 작동
만약 위 setInterval 내부에서 일반 함수를 사용했다면, this는 전역 객체(Window 또는 global)를 가리켜 undefined++가 발생했을 것입니다.
3. 생성자 함수(Constructor) 사용 여부
화살표 함수는 객체를 생성하는 생성자로 사용할 수 없습니다.
일반 함수
일반 함수는 new 키워드와 함께 사용하여 새로운 인스턴스를 만들 수 있습니다.
function Person(name) {
this.name = name;
}
const me = new Person("홍길동"); // 성공
화살표 함수
화살표 함수는 prototype 프로퍼티가 없으며, 내부적으로 [[Construct]] 메서드가 구현되어 있지 않아 new와 함께 호출하면 에러가 발생합니다.
const Robot = (model) => {
this.model = model;
};
const myRobot = new Robot("K-1"); // TypeError: Robot is not a constructor
4. arguments 객체
함수 내부에서 전달된 인자들을 확인할 수 있는 arguments 객체의 유무도 차이점입니다.
일반 함수
function showArgs() {
console.log(arguments);
}
showArgs(1, 2, 3); // [1, 2, 3] 형태의 유사 배열 객체 출력
화살표 함수
화살표 함수는 arguments 변수가 없습니다. 대신 상위 스코프의 arguments에 접근하게 되며, 자신의 인자를 확인하려면 Rest 파라미터를 사용해야 합니다.
const showArgsArrow = (...args) => {
console.log(args);
};
showArgsArrow(10, 20, 30); // [10, 20, 30] 실제 배열 출력 (권장 방식)
5. 메서드로 사용 시 주의사항
객체의 메서드를 정의할 때 화살표 함수를 사용하면 위험할 수 있습니다.
const counter = {
value: 0,
increase: () => {
// 여기서 this는 counter가 아니라 전역 객체를 가리킴!
this.value++;
}
};
counter.increase();
console.log(counter.value); // 0 (변화 없음)
객체의 메서드를 정의할 때는 일반 함수(또는 ES6의 메서드 축약형)를 사용하는 것이 안전합니다.
요약: 무엇을 써야 할까?
구분일반 함수 (Regular Function)화살표 함수 (Arrow Function)
| this | 호출 방식에 따라 동적 결정 | 선언 시점의 상위 스코프 고정 |
| 생성자 | 가능 (new 사용 가능) | 불가능 |
| arguments | 존재함 | 존재하지 않음 (Rest 파라미터 사용) |
| 용도 | 메서드, 생성자 함수 | 콜백 함수, 간결한 로직, this 고정이 필요할 때 |
결론적으로:
- 객체의 메서드를 만들거나 생성자로 쓸 때는 일반 함수를 사용하세요.
- setTimeout, map, filter 등의 콜백 함수 내부에서 상위 스코프의 this를 유지하고 싶을 때는 화살표 함수가 최적의 선택입니다.