화살표 함수 (Arrow Function)
이 토픽을 마치면
화살표 함수의 문법을 자유롭게 쓸 수 있고, 일반 함수와의 핵심 차이(this 바인딩)를 설명할 수 있으며, 언제 화살표 함수를 쓰고 언제 피해야 하는지 판단할 수 있습니다.
function 키워드에서 화살표로
ES6 이전에는 함수를 만들 때 항상 function 키워드를 썼습니다:
const add = function(a, b) {
return a + b;
};화살표 함수로 바꾸면:
const add = (a, b) => {
return a + b;
};본문이 표현식 하나뿐이면 중괄호와 return을 생략할 수 있습니다:
const add = (a, b) => a + b;매개변수가 하나뿐이면 괄호도 생략 가능:
const double = x => x * 2;문법 변형 정리
// 매개변수 없음 — 괄호 필수
const greet = () => "안녕하세요";
// 매개변수 1개 — 괄호 생략 가능
const square = x => x * x;
// 매개변수 2개 이상 — 괄호 필수
const sum = (a, b) => a + b;
// 본문이 여러 줄 — 중괄호 + return 필수
const calculate = (a, b) => {
const result = a * b;
console.log(result);
return result;
};
// 객체를 반환할 때 — 소괄호로 감싸기
const makeUser = (name) => ({ name: name, role: "user" });마지막 패턴이 자주 헷갈립니다. { name: name }을 그냥 쓰면 JavaScript가 함수 본문의 중괄호로 해석합니다. 소괄호 ()로 감싸야 "이건 객체 리터럴이야"라고 알려줍니다.
콜백에서 빛나는 화살표 함수
배열 메서드의 콜백으로 쓸 때 화살표 함수가 가장 자연스럽습니다:
const numbers = [1, 2, 3, 4, 5];
// 일반 함수
const doubled = numbers.map(function(n) {
return n * 2;
});
// 화살표 함수
const doubled = numbers.map(n => n * 2);filter, reduce, forEach, sort 등 배열 메서드에서 매번 function 키워드를 쓰면 코드가 길어지고 핵심 로직이 묻힙니다. 화살표 함수가 채택된 가장 큰 이유입니다.
// 실무 패턴: 체이닝
const result = users
.filter(u => u.age >= 18)
.map(u => u.name)
.sort((a, b) => a.localeCompare(b));this — 가장 중요한 차이
일반 함수의 this는 호출 방식에 따라 결정됩니다. 화살표 함수의 this는 선언 위치에서 결정됩니다:
const timer = {
seconds: 0,
// ❌ 일반 함수 — this가 window를 가리킴
startBroken: function() {
setInterval(function() {
this.seconds++; // this === window (또는 undefined in strict)
console.log(this.seconds); // NaN
}, 1000);
},
// ✅ 화살표 함수 — this가 timer 객체를 가리킴
start: function() {
setInterval(() => {
this.seconds++; // this === timer
console.log(this.seconds); // 1, 2, 3...
}, 1000);
}
};setInterval에 일반 함수를 넘기면, 그 함수가 실행될 때 this는 전역 객체(window)가 됩니다. 콜백의 this가 의도와 달라지는 건 JavaScript 최대 함정 중 하나였습니다.
화살표 함수는 자신만의 this를 만들지 않습니다. 대신 선언된 바깥 스코프의 this를 그대로 씁니다. 이것을 lexical this라고 합니다.
ES6 이전에는 이 문제를 우회하려고 var self = this;나 .bind(this)를 썼습니다:
// ES5 시절 우회법
start: function() {
var self = this;
setInterval(function() {
self.seconds++;
}, 1000);
}화살표 함수가 이 패턴을 완전히 대체했습니다.
화살표 함수를 쓰면 안 되는 곳
1. 객체 메서드
const user = {
name: "철수",
// ❌ 화살표 — this가 user가 아님
greet: () => {
console.log(`안녕, ${this.name}`); // undefined
},
// ✅ 일반 함수 축약 — this가 user
greet() {
console.log(`안녕, ${this.name}`); // "안녕, 철수"
}
};객체 리터럴의 메서드로 화살표 함수를 쓰면, this가 객체가 아니라 바깥 스코프(보통 전역)를 가리킵니다.
2. 생성자
// ❌ 화살표 함수로 생성자 불가
const Person = (name) => { this.name = name; };
new Person("철수"); // TypeError: Person is not a constructor화살표 함수에는 prototype이 없어서 new 키워드를 쓸 수 없습니다.
3. DOM 이벤트 핸들러에서 this가 필요할 때
// ❌ 화살표 — this가 버튼이 아님
button.addEventListener("click", () => {
this.classList.toggle("active"); // this !== button
});
// ✅ 일반 함수 — this가 이벤트 대상 요소
button.addEventListener("click", function() {
this.classList.toggle("active"); // this === button
});단, event.target이나 event.currentTarget으로 대체 가능하므로 화살표 함수를 써도 되는 경우가 많습니다.
화살표 함수에 없는 것들
| 기능 | 일반 함수 | 화살표 함수 |
|---|---|---|
| 자체 this | ✅ | ❌ (lexical) |
| arguments 객체 | ✅ | ❌ |
| new 호출 (생성자) | ✅ | ❌ |
| prototype | ✅ | ❌ |
| super | ✅ | ❌ (lexical) |
arguments가 없는 대신 나머지 매개변수(...args)를 씁니다:
// 일반 함수
function sum() {
return [...arguments].reduce((a, b) => a + b, 0);
}
// 화살표 함수
const sum = (...args) => args.reduce((a, b) => a + b, 0);...args가 arguments보다 명시적이고 배열 메서드를 바로 쓸 수 있어서, 오히려 화살표 함수의 방식이 권장됩니다.
판단 기준
콜백 함수인가? → 화살표 함수
배열 메서드 (map/filter/...)인가? → 화살표 함수
객체의 메서드인가? → 일반 함수 (축약 문법)
생성자가 필요한가? → 일반 함수 (or class)
this를 동적으로 바꿔야 하는가? → 일반 함수핵심 한 줄: 화살표 함수는
() => {}로 쓰고, 바깥 스코프의 this를 그대로 씁니다(lexical this). 콜백에서는 화살표, 객체 메서드에서는 일반 함수 — 이것만 기억하면 됩니다.