본문으로 건너뛰기

안동민 개발노트

본문 시작

화살표 함수와 this

화살표 함수의 축약 문법과 외부 this를 캡처하는 특성을 익히고 메서드·생성자처럼 피해야 할 위치를 구분합니다.

우리는 6장 자바스크립트 심화 I에서 this가 호출 방식에 따라 동적으로 바인딩된다는 점을 학습했습니다.

이 특성은 콜백/중첩 함수에서 혼란을 만들었고, bind, call, apply, self = this 같은 우회 패턴을 자주 요구했습니다.

ES2015(ES6)에서 도입된 화살표 함수(Arrow Function)는 이러한 this 바인딩 문제를 근본적으로 해결하는 동시에, 함수를 선언하는 문법을 훨씬 간결하게 만들어 주었습니다.

화살표 함수는 모던 자바스크립트 코드에서 거의 필수적으로 사용되는 기능이 되었으므로, 정확한 이해가 중요합니다.

이번 장에서는 화살표 함수 기본 문법, this 바인딩 차이, 일반 함수와의 사용 시나리오를 비교해 정리합니다.

화살표 함수와 this

일반 함수의 this는 호출 방식에 따라 바뀌지만, 화살표 함수는 바깥 렉시컬 this를 그대로 사용합니다. 콜백과 메서드 경계를 구분해야 합니다.

  1. 화살표 함수의 기본 문법

    화살표 함수는 function 키워드 대신 화살표 = 를 사용하여 함수를 정의하는 간결한 문법입니다. 자바스크립트 심화 I

  2. 화살표 함수와 this 바인딩의 차이점

    this를 새로 바인딩하지 않는 동작이 화살표 함수를 사용하는 핵심 이유입니다. 화살표 함수(Arrow Function)

  3. 화살표 함수를 사용하지 말아야 할 경우

    화살표 함수는 매우 편리하지만, 모든 상황에서 기존 함수를 대체할 수 있는 것은 아닙니다. 매개변수가 하나일 때

  4. 화살표 함수와 this 기준

    정확성 일반 함수의 this는 호출 방식이 결정하고, 화살표 함수의 this는 선언된 바깥 스코프가 결정합니다. 비용 화살표 함수는 자신만의 this를 만들지 않아 콜백에서 발생하는 this 바인딩 혼란을 줄입니다. 확장성 화살표 함수는 매개변수 => 표현식 또는 매개변수 => { 함수 본문 }으로 작성하며, 매개변수가 하나면 괄호를 생략할 수 있습니다. 예외 매개변수가 없을 때: 빈 괄호를 사용해야 합니다.

  5. 정확성 일반 함수의 this

    호출 방식이 결정하고, 화살표 함수의 this는 선언된 바깥 스코프가 결정합니다.

  6. 비용 화살표 함수

    자신만의 this를 만들지 않아 콜백에서 발생하는 this 바인딩 혼란을 줄입니다.

  7. 확장성 화살표 함수

    매개변수 => 표현식 또는 매개변수 => { 함수 본문 }으로 작성하며, 매개변수가 하나면 괄호를 생략할 수 있습니다.

  8. 예외 매개변수가 없을 때

    빈 괄호를 사용해야 합니다.


화살표 함수의 기본 문법

화살표 함수는 function 키워드 대신 화살표 =>를 사용하여 함수를 정의하는 간결한 문법입니다.

기본 형태

매개변수 => 표현식 또는 { 함수 본문 }

// 기존 함수 표현식
const add = function(a, b) {
    return a + b;
};

// 화살표 함수 (기본 형태)
const addArrow = (a, b) => a + b; // 중괄호와 return이 생략됨
console.log(addArrow(2, 3)); // 결과: 5

다양한 형태

매개변수가 하나일 때: 괄호를 생략할 수 있습니다.

const greet = name => `Hello, ${name}!`;
console.log(greet("Alice")); // 결과: Hello, Alice!

매개변수가 없을 때: 빈 괄호를 사용해야 합니다.

const sayHi = () => "Hi there!";
console.log(sayHi()); // 결과: Hi there!

함수 본문이 여러 줄일 때: 중괄호를 사용하고 명시적으로 return 키워드를 사용해야 합니다.

const calculateSum = (numbers) => {
    let sum = 0;
    for (let num of numbers) {
        sum += num;
    }
    return sum;
};
console.log(calculateSum([1, 2, 3, 4, 5])); // 결과: 15

객체 리터럴을 반환할 때: 소괄호로 감싸야 합니다.

(중괄호가 함수 본문으로 해석되는 것을 방지)

const createUser = (name, age) => ({ name: name, age: age });
console.log(createUser("Bob", 28)); // 결과: { name: 'Bob', age: 28 }

화살표 함수와 this 바인딩의 차이점

화살표 함수와 this에서는 값의 변화, 실행 순서, 화면 반응을 함께 봅니다.

화살표 함수 this

this는 함수가 어떻게 호출됐는지로 정해지지만 화살표 함수는 자신만의 this를 만들지 않고 바깥 this를 캡처한다.

상황일반 함수화살표 함수선택 기준
Object method호출 객체가 this바깥 this 사용객체 상태를 읽으면 일반 함수
Callback호출자가 this를 정함상위 this 유지this 손실을 막고 싶으면 화살표
Event listener리스너 대상이 this가 될 수 있음외부 상태를 this로 사용DOM 요소가 필요한지 확인
Constructornew와 prototype 사용 가능new 불가인스턴스 생성이면 일반 함수/class
arguments자신의 arguments 있음바깥 arguments 참조가변 인자는 rest parameter 사용

이것이 화살표 함수를 사용하는 가장 큰 이유이자 가장 중요한 특징입니다.

기존의 function 키워드로 선언된 함수는 호출 방식에 따라 this가 동적으로 결정됩니다.

하지만 화살표 함수는 this를 자신이 선언될 때의 상위 스코프(Lexical Scope)에서 가져옵니다.

즉, this가 정적으로 바인딩됩니다.

기존 함수의 this

const person = {
    name: "Minjun",
    // 1. 메서드로서 호출: `.` 앞의 객체(person)가 `this`가 됨
    sayHello: function() {
        console.log(`Hello, my name is ${this.name}.`);
    },
    // 2. 중첩 함수에서 `this` 문제 발생
    greetDelayed: function() {
        // 기존 함수의 `this` (person)를 유지하기 위한 꼼수: `self = this`
        const self = this;
        setTimeout(function() { // setTimeout의 콜백 함수는 일반 함수이므로 `this`가 전역 객체(window)를 가리킴
            console.log(`Delayed Hello, my name is ${self.name}. (using self)`);
            // console.log(`Delayed Hello, my name is ${this.name}. (using this - WRONG!)`);
        }, 500);
    }
};

person.sayHello(); // 결과: Hello, my name is Minjun.
person.greetDelayed(); // 결과: Delayed Hello, my name is Minjun. (using self)
                       // WRONG! 줄은 undefined가 출력되거나 에러 발생

위 예시에서 setTimeout 내부의 function() { ... }은 일반 함수이므로 thiswindow (브라우저) 또는 undefined (엄격 모드)를 가리킵니다.

그래서 this.name은 제대로 된 값을 가져오지 못합니다.

화살표 함수의 this

화살표 함수는 자신이 정의될 때의 상위 스코프의 this를 그대로 가져옵니다.

절대 자기 자신만의 this 바인딩을 생성하지 않습니다.
const personArrow = {
    name: "Seulgi",
    sayHello: () => { // 화살표 함수가 최상위 스코프에 정의되면 `this`는 `window`를 가리킴
        console.log(`Hello, my name is ${this.name}. (WRONG! - window or undefined)`);
    },
    greetDelayed: function() { // 이 함수는 일반 함수이므로 `this`는 `personArrow`를 가리킴
        // 화살표 함수는 자신의 상위 스코프(greetDelayed)의 `this`를 가져옴
        setTimeout(() => {
            console.log(`Delayed Hello, my name is ${this.name}. (using arrow function)`);
        }, 500);
    }
};

personArrow.sayHello(); // 결과: Hello, my name is . (window.name이 없거나 undefined)
                        // 주의: 객체의 메서드로 최상위 화살표 함수 사용은 권장되지 않음

personArrow.greetDelayed(); // 결과: Delayed Hello, my name is Seulgi. (using arrow function)

personArrow.greetDelayed 내부의 setTimeout 콜백은 화살표 함수로 정의되었습니다.

이 화살표 함수는 자신이 선언된 greetDelayed 함수 스코프의 this 값을 그대로 가져옵니다.

greetDelayedpersonArrow 객체의 메서드로 호출되었으므로, greetDelayed 내부의 thispersonArrow를 가리킵니다.

따라서 화살표 함수 내부의 thispersonArrow를 가리키게 되어 원하는 대로 동작합니다.

핵심: 화살표 함수는 this 바인딩에 대한 문제를 해결해주는 강력한 도구입니다.

특히 콜백 함수에서 this 컨텍스트를 유지해야 할 때 유용합니다.


화살표 함수를 사용하지 말아야 할 경우

화살표 함수는 매우 편리하지만, 모든 상황에서 기존 함수를 대체할 수 있는 것은 아닙니다.

this 바인딩 방식의 차이 때문에 특정 상황에서는 기존 함수를 사용해야 합니다.

객체의 메서드를 정의할 때 (최상위 메서드): 위 personArrow.sayHello() 예시에서 보았듯이, 객체 리터럴의 최상위 메서드를 화살표 함수로 정의하면 this가 객체 자신이 아닌 전역 객체를 가리키게 되어 의도치 않은 결과를 초래합니다.

const myObject = {
    value: 10,
    // BAD: 화살표 함수는 this가 상위 스코프 (window/global)를 가리킴
    getValueArrow: () => {
        console.log(this.value); // undefined (또는 window.value)
    },
    // GOOD: 일반 함수는 `.` 호출 시 myObject를 this로 바인딩
    getValueNormal: function() {
        console.log(this.value); // 10
    }
};

myObject.getValueArrow();
myObject.getValueNormal();

객체의 메서드는 항상 일반 함수(또는 ES6의 메서드 축약형 method() { ... })로 정의해야 합니다.

생성자 함수 (Constructor): 화살표 함수는 prototype 프로퍼티를 가지지 않으며, new 키워드와 함께 호출될 수 없습니다.

new와 함께 호출하면 TypeError가 발생합니다.

// BAD: 화살표 함수는 생성자로 사용할 수 없음
// const MyClass = () => { this.value = 1; };
// const instance = new MyClass(); // TypeError: MyClass is not a constructor

// GOOD: 생성자는 일반 함수 또는 class 키워드로 정의
function MyClass(value) {
    this.value = value;
}
const instance = new MyClass(10);

arguments 객체에 접근해야 할 때: 화살표 함수는 arguments 객체를 바인딩하지 않습니다.

대신 상위 스코프의 arguments를 참조합니다.

기존 함수는 자신에게 전달된 인자들을 arguments 객체로 접근할 수 있습니다.

(ES6에서는 ...rest 매개변수 사용이 더 권장되긴 합니다.)

function sumAllNormal() {
    console.log(arguments); // [1, 2, 3]
    return Array.from(arguments).reduce((a, b) => a + b);
}
console.log(sumAllNormal(1, 2, 3)); // 결과: 6

const sumAllArrow = () => {
    // console.log(arguments); // ReferenceError: arguments is not defined (상위 스코프에 arguments 없으면)
    // 화살표 함수에서는 ...rest 매개변수를 사용해야 함
    // return [...arguments].reduce((a, b) => a + b); // Error!
};
// console.log(sumAllArrow(1, 2, 3));

addEventListener 등 이벤트 핸들러: 특정 DOM 요소에 이벤트 리스너를 붙일 때, this는 기본적으로 이벤트를 발생시킨 요소를 가리킵니다.

화살표 함수를 사용하면 이 this 바인딩이 깨져 의도치 않은 결과를 초래할 수 있습니다.

<button id="myButton">클릭하세요</button>
<script>
    const button = document.getElementById('myButton');

    // GOOD: 일반 함수는 this가 버튼 요소 자체를 가리킴
    button.addEventListener('click', function() {
        console.log("일반 함수 this:", this.id); // 결과: myButton
    });

    // BAD: 화살표 함수는 this가 상위 스코프 (window)를 가리킴
    button.addEventListener('click', () => {
        console.log("화살표 함수 this:", this.id); // 결과: undefined (window.id는 없음)
    });
</script>

DOM 이벤트처럼 호출 주체가 중요한 코드는 아래 흐름으로 일반 함수와 화살표 함수를 구분해 선택합니다.

DOM 이벤트에서 this 선택하기

이벤트 리스너는 DOM 요소 자체가 필요한지, 바깥 객체 상태가 필요한지에 따라 일반 함수와 화살표 함수를 다르게 고른다.

필요한 것일반 함수가 맞는 경우화살표 함수가 맞는 경우확인할 API
Clicked elementthis가 리스너 대상이어야 함event.currentTarget을 쓰면 대체 가능currentTarget
Outer statethis를 따로 bind해야 함상위 this를 그대로 캡처class field, closure
Delegation부모에서 이벤트를 받고 event.target으로 실제 요소 확인화살표도 가능target.closest
Remove listener같은 함수 참조가 필요익명 화살표는 제거 어려움handler 변수 보관
ReadabilityDOM this가 의미를 드러냄외부 상태 접근이 선명팀 규칙을 통일

화살표 함수·this 정리

정리 단계에서는 문법 간결성보다 this 바인딩이 코드 유지보수성에 주는 효과를 우선 확인합니다.

화살표 함수 선택 기준표

화살표 함수는 바깥 this를 고정하고, 일반 함수는 호출한 주체에 따라 this가 결정됩니다.

  1. 화살표 함수 선택 기준표 함수

    형태별 this 결정 방식 화살표 함수는 바깥 this를 고정하고, 일반 함수는 호출한 주체에 따라 this가 결정됩니다.

  2. Arrow Function 바깥 문맥

    유지해야 할 때 콜백과 배열 메서드처럼 호출 주체보다

  3. 주변 스코프

    더 중요할 때 잘 맞습니다.

이번 장에서는 ES2015(ES6)의 핵심 기능인 화살표 함수(Arrow Function)의 간결한 문법과, 특히 개발자들을 혼란스럽게 했던 this 바인딩 문제를 어떻게 해결하는지에 대해 심도 있게 학습했습니다.

화살표 함수는 선언 위치의 상위 스코프 this를 그대로 사용하는 렉시컬 this 바인딩을 갖습니다.

콜백이나 중첩 함수에서 this가 바뀌면 안 되는 경우에 이 특성이 도움이 됩니다.

하지만 화살표 함수가 모든 상황에서 기존 함수의 대안이 될 수는 없다는 점도 중요하게 다루었습니다.

객체의 메서드, 생성자 함수, arguments 객체에 접근해야 할 때, 그리고 이벤트 리스너의 this 바인딩이 중요한 경우에는 여전히 기존 함수(또는 class 문법의 메서드)를 사용해야 합니다.

화살표 함수는 간결하지만 생성자 함수나 자체 this가 필요한 메서드에는 맞지 않습니다.

짧은 콜백에는 적합하고, 객체 메서드의 this가 중요한 경우에는 일반 함수와 비교해 선택해야 합니다.

마지막으로 함수 형태를 고를 때는 짧은 문법보다 this가 어디서 정해져야 하는지를 먼저 묻는 습관이 중요합니다.

화살표 함수 this 체크

화살표 함수는 자신의 this를 만들지 않으므로 콜백에는 유리하지만 메서드와 생성자 역할에는 맞지 않는 경우가 많다.

질문화살표 사용일반 함수 사용주의점
상위 this가 필요한가예, 캡처가 목적아니오this 값이 어디서 오는지 기록
호출 객체가 this여야 하나부적합obj.method에 적합메서드 분리 대입 주의
new로 호출할 함수인가불가생성자/class 사용prototype 없음
arguments가 필요한가rest parameter 사용arguments 사용 가능명시적 인자를 선호
이벤트 대상이 필요한가event.currentTarget 권장this로 DOM 대상 접근 가능팀 규칙을 정함
화살표 함수: 짧은 문법이 아니라 this 캡처 규칙

화살표 함수는 자신만의 this, arguments, prototype을 만들지 않아 바깥 this 유지에는 강하지만 메서드나 생성자에는 맞지 않는다.

특징의미좋은 사용처피할 자리
No own this바깥 lexical this 사용setTimeout, Promise callback객체 메서드
No arguments자기 arguments 없음rest parameter로 대체arguments가 필요한 함수
No prototype생성자로 사용할 수 없음짧은 콜백new 호출 대상
Expression body짧은 반환 표현 가능map/filter 콜백복잡한 로직을 한 줄에 압축
Readability콜백 의도 명확상위 상태 유지this 출처가 오히려 숨겨짐
화살표 함수와 this 캡처

화살표 함수는 짧게 쓰는 함수 문법이 아니라 자신만의 this를 만들지 않고 바깥 lexical scope의 this를 그대로 쓴다.

상황결과좋은 패턴위험 패턴
Class callback인스턴스 this 유지field arrow handler불필요한 bind 반복
Array callbackthis보다 값 변환이 핵심map/filter arrow복잡한 side effect 숨김
Object literal객체가 this가 되지 않음일반 method syntax 사용arrow method로 this undefined
DOM listener바깥 this 유지event.currentTarget 사용this가 DOM일 거라 기대
Nested function바깥 문맥 보존짧은 내부 콜백어느 this인지 추적 불가