第8講

화살표 함수와 스코프

4 閲覧 1

화살표 함수의 간결한 문법과 this 바인딩 차이를 정확히 이해한다. 렉시컬 스코프와 클로저의 동작 원리를 익히고, 클로저를 실무에서 활용하는 패턴을 배운다.

화살표 함수 — 간결함 그 이상

화살표 함수(Arrow Function)는 ES6에서 도입된 함수 표현 방식입니다. 단순히 짧게 쓰는 문법이 아니라, this 바인딩이 완전히 다르게 동작한다는 핵심 차이가 있습니다.

화살표 함수 문법

// 기본 비교
const add = function(a, b) { return a + b; }; // 일반 함수
const add = (a, b) => a + b;                  // 화살표 함수

// 매개변수 규칙
() => "값"           // 매개변수 없음
x => x * 2           // 매개변수 1개 → 괄호 생략 가능
(x, y) => x + y      // 매개변수 2개 이상 → 괄호 필수

// 본문 규칙
x => x * 2                        // 단일 표현식 → return 생략
x => { return x * 2; }            // 블록 본문 → return 명시
x => ({ id: x, value: x * 2 })    // 객체 반환 → 소괄호로 감싸기!

// 잘못된 예
x => { id: x } // 에러! — {}가 블록으로 해석됨
x => ({ id: x }) // 올바름 — ()로 객체임을 표시

this 바인딩 — 핵심 차이

일반 함수는 호출 방식에 따라 this가 동적으로 결정됩니다. 화살표 함수는 선언된 위치의 this를 그대로 사용(렉시컬 this)합니다.

// 일반 함수의 this 문제
const timer = {
  count: 0,
  start: function() {
    setInterval(function() {
      this.count++; // this가 window/undefined (콜백에서 this 변경됨)
      console.log(this.count); // NaN
    }, 1000);
  }
};

// 화살표 함수로 해결
const timer2 = {
  count: 0,
  start: function() {
    setInterval(() => {
      this.count++; // this가 timer2 (화살표 함수는 상위 this 상속)
      console.log(this.count); // 1, 2, 3, ...
    }, 1000);
  }
};

// 메서드에는 화살표 함수 쓰지 마세요
const obj = {
  name: "Kim",
  greet: () => {
    console.log(this.name); // undefined — 화살표 함수는 obj의 this를 갖지 않음
  }
};
obj.greet(); // undefined

// 메서드는 일반 함수로
const obj2 = {
  name: "Kim",
  greet() { // 메서드 단축 표기
    console.log(this.name); // "Kim"
  }
};

스코프(Scope) — 변수의 유효 범위

// 전역 스코프
const globalVar = "전역";

function outer() {
  const outerVar = "외부"; // 함수 스코프

  if (true) {
    const blockVar = "블록"; // 블록 스코프
    console.log(globalVar);  // 접근 가능
    console.log(outerVar);   // 접근 가능
    console.log(blockVar);   // 접근 가능
  }

  console.log(globalVar);    // 접근 가능
  console.log(outerVar);     // 접근 가능
  // console.log(blockVar);  // ReferenceError!
}

// console.log(outerVar); // ReferenceError!

스코프 체인

변수를 찾을 때 현재 스코프부터 시작해 바깥 스코프로 순서대로 탐색합니다.

const x = "전역";

function outer() {
  const x = "외부";

  function inner() {
    const x = "내부";
    console.log(x); // "내부" (가장 가까운 스코프)
  }

  function inner2() {
    console.log(x); // "외부" (inner2에 없으면 outer로)
  }

  inner();
  inner2();
}

outer();

클로저(Closure) — 자바스크립트의 핵심 개념

클로저는 함수가 자신이 선언된 스코프의 변수를 기억하고 접근할 수 있는 현상입니다. 함수가 반환된 후에도 외부 스코프 변수를 살려둡니다.

function makeCounter() {
  let count = 0; // makeCounter의 지역 변수

  return {
    increment() { return ++count; },
    decrement() { return --count; },
    getCount() { return count; }
  };
}

const counter = makeCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount());  // 1

// count는 외부에서 직접 접근 불가 (캡슐화!)
console.log(counter.count); // undefined

// 독립적인 카운터
const counter2 = makeCounter();
counter2.increment();
console.log(counter2.getCount()); // 1 (counter와 독립)

클로저 실무 활용 패턴

// 1. 함수 팩토리
function multiplier(factor) {
  return (n) => n * factor;
}
const double = multiplier(2);
const triple = multiplier(3);
[1, 2, 3].map(double); // [2, 4, 6]

// 2. 메모이제이션 (캐싱)
function memoize(fn) {
  const cache = {};
  return function(n) {
    if (n in cache) return cache[n];
    cache[n] = fn(n);
    return cache[n];
  };
}

const expensiveCalc = memoize(function(n) {
  // 복잡한 계산...
  return n * n;
});
expensiveCalc(10); // 계산 후 캐시
expensiveCalc(10); // 캐시에서 즉시 반환

// 3. 이벤트 핸들러에서 데이터 캡처
function attachClickHandlers(buttons) {
  buttons.forEach((button, index) => {
    button.addEventListener("click", () => {
      console.log(`버튼 ${index} 클릭됨`);
      // index가 클로저로 캡처됨
    });
  });
}

클로저 함정 — var와 루프

// 유명한 var + 클로저 버그
for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// 출력: 3, 3, 3 (예상: 0, 1, 2)
// var는 함수 스코프라 같은 i를 공유함

// 해결 1: let 사용 (블록 스코프)
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// 출력: 0, 1, 2 ✅

// 해결 2: IIFE로 스코프 생성 (구식 방법)
for (var i = 0; i < 3; i++) {
  (function(j) {
    setTimeout(() => console.log(j), 100);
  })(i);
}

관련 검색어  ·  화살표 함수 this, 자바스크립트 클로저, 렉시컬 스코프, 클로저 활용 패턴, 스코프 체인, 메모이제이션

채용정보
공지사항
인사이트
MY