본문 바로가기
  • 코딩, 허쌤이 떠먹여 줄게
FrontEnd/Javascript

13장. 스코프와 호이스팅

by 허쌤 2026. 1. 12.

13장. 스코프와 호이스팅

스코프 (Scope)란?

스코프(Scope)는 변수나 함수에 접근할 수 있는 범위를 의미합니다. JavaScript에는 여러 종류의 스코프가 있습니다.


1. 스코프의 종류

전역 스코프 (Global Scope)

함수나 블록 밖에서 선언된 변수는 전역 스코프를 가집니다.

let globalVar = '전역 변수';

function test() {
    console.log(globalVar);  // 접근 가능
}

console.log(globalVar);  // 접근 가능

함수 스코프 (Function Scope)

함수 내부에서 선언된 변수는 함수 스코프를 가집니다.

function test() {
    let functionVar = '함수 변수';
    console.log(functionVar);  // 접근 가능
}

// console.log(functionVar);  // ReferenceError (접근 불가)

블록 스코프 (Block Scope)

letconst는 블록 스코프를 가집니다.

if (true) {
    let blockVar = '블록 변수';
    console.log(blockVar);  // 접근 가능
}

// console.log(blockVar);  // ReferenceError (접근 불가)

2. var, let, const의 스코프

var: 함수 스코프

function test() {
    if (true) {
        var x = 10;
    }
    console.log(x);  // 10 (블록을 무시하고 함수 스코프)
}

// console.log(x);  // ReferenceError (함수 밖에서는 접근 불가)

let, const: 블록 스코프

function test() {
    if (true) {
        let y = 10;
        const z = 20;
    }
    // console.log(y);  // ReferenceError
    // console.log(z);  // ReferenceError
}

스코프 비교 예제

// var: 함수 스코프
function test1() {
    for (var i = 0; i < 3; i++) {
        // ...
    }
    console.log(i);  // 3 (접근 가능)
}

// let: 블록 스코프
function test2() {
    for (let j = 0; j < 3; j++) {
        // ...
    }
    // console.log(j);  // ReferenceError (접근 불가)
}

3. 스코프 체인 (Scope Chain)

변수를 찾을 때 현재 스코프에서 시작하여 상위 스코프로 올라가며 찾습니다.

let global = '전역';

function outer() {
    let outerVar = '외부';

    function inner() {
        let innerVar = '내부';
        console.log(innerVar);  // '내부' (현재 스코프)
        console.log(outerVar);  // '외부' (상위 스코프)
        console.log(global);    // '전역' (전역 스코프)
    }

    inner();
}

outer();

4. 호이스팅 (Hoisting)이란?

호이스팅(Hoisting)은 변수와 함수 선언이 코드의 최상단으로 끌어올려지는 것처럼 동작하는 JavaScript의 특징입니다.

var의 호이스팅

console.log(x);  // undefined (오류가 아님!)
var x = 10;

위 코드는 다음과 같이 동작합니다:

var x;  // 선언이 끌어올려짐
console.log(x);  // undefined
x = 10;

let, const의 호이스팅

// console.log(y);  // ReferenceError (TDZ)
let y = 10;

// console.log(z);  // ReferenceError (TDZ)
const z = 20;

letconst도 호이스팅되지만, TDZ(Temporal Dead Zone) 때문에 선언 전에 접근할 수 없습니다.


5. 함수 호이스팅

함수 선언 (Function Declaration)

함수 선언은 완전히 호이스팅됩니다.

sayHello();  // ✅ 동작함!

function sayHello() {
    console.log('Hello');
}

위 코드는 다음과 같이 동작합니다:

function sayHello() {  // 함수 선언이 끌어올려짐
    console.log('Hello');
}

sayHello();  // ✅ 동작함!

함수 표현식 (Function Expression)

함수 표현식은 호이스팅되지 않습니다.

// sayHi();  // ❌ TypeError

const sayHi = function() {
    console.log('Hi');
};

sayHi();  // ✅ 동작함

화살표 함수

화살표 함수도 호이스팅되지 않습니다.

// sayBye();  // ❌ ReferenceError

const sayBye = () => {
    console.log('Bye');
};

sayBye();  // ✅ 동작함

6. 호이스팅 예제

예제 1: var의 호이스팅

console.log(a);  // undefined
var a = 10;
console.log(a);  // 10

예제 2: let의 TDZ

// console.log(b);  // ReferenceError: Cannot access 'b' before initialization
let b = 20;
console.log(b);  // 20

예제 3: 함수 선언 호이스팅

test();  // ✅ "함수 실행됨"

function test() {
    console.log('함수 실행됨');
}

예제 4: 함수 표현식은 호이스팅 안 됨

// test2();  // ❌ TypeError: test2 is not a function

var test2 = function() {
    console.log('함수 실행됨');
};

test2();  // ✅ "함수 실행됨"

7. 스코프와 클로저 (Closure)

클로저(Closure)는 내부 함수가 외부 함수의 변수에 접근할 수 있는 현상입니다.

function outer() {
    let count = 0;

    function inner() {
        count++;
        console.log(count);
    }

    return inner;
}

const counter = outer();
counter();  // 1
counter();  // 2
counter();  // 3

클로저 활용 예제

function createCounter() {
    let count = 0;

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

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

8. var의 문제점과 let/const 사용

var의 문제점

// 문제 1: 함수 스코프만 인식
for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);  // 3, 3, 3 (예상과 다름!)
    }, 100);
}

// 문제 2: 중복 선언 가능
var x = 10;
var x = 20;  // 오류 없이 덮어씀

// 문제 3: 호이스팅으로 인한 혼란
console.log(y);  // undefined (오류가 아님!)
var y = 10;

let/const 사용 (권장)

// 해결 1: 블록 스코프
for (let i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);  // 0, 1, 2 (올바름!)
    }, 100);
}

// 해결 2: 중복 선언 불가
let x = 10;
// let x = 20;  // SyntaxError

// 해결 3: TDZ로 명확한 오류
// console.log(y);  // ReferenceError
let y = 10;

9. 실전 예제

예제 1: 스코프 체인

let global = '전역';

function level1() {
    let level1Var = '레벨 1';

    function level2() {
        let level2Var = '레벨 2';

        function level3() {
            let level3Var = '레벨 3';
            console.log(level3Var);  // '레벨 3'
            console.log(level2Var);  // '레벨 2'
            console.log(level1Var);  // '레벨 1'
            console.log(global);     // '전역'
        }

        level3();
    }

    level2();
}

level1();

예제 2: 클로저로 프라이빗 변수

function createBankAccount(initialBalance) {
    let balance = initialBalance;  // 프라이빗 변수

    return {
        deposit: function(amount) {
            balance += amount;
            return balance;
        },
        withdraw: function(amount) {
            if (amount <= balance) {
                balance -= amount;
                return balance;
            } else {
                return '잔액 부족';
            }
        },
        getBalance: function() {
            return balance;
        }
    };
}

const account = createBankAccount(1000);
console.log(account.getBalance());    // 1000
console.log(account.deposit(500));    // 1500
console.log(account.withdraw(200));   // 1300
// console.log(balance);  // ReferenceError (직접 접근 불가)

주의사항

1. 전역 변수 남용

// ❌ 전역 변수 남용
var x = 10;
var y = 20;
var z = 30;

// ✅ 객체로 묶기
const config = {
    x: 10,
    y: 20,
    z: 30
};

2. var 대신 let/const 사용

// ❌ var 사용
for (var i = 0; i < 3; i++) {
    // ...
}

// ✅ let 사용
for (let i = 0; i < 3; i++) {
    // ...
}

3. 호이스팅 이해

// 호이스팅으로 인한 혼란 방지
// 함수는 선언 후에 호출하는 것이 좋음
function test() {
    // ...
}

test();  // 선언 후 호출

연습 문제

  1. 스코프 이해
    • 다음 코드의 출력 결과를 예상하세요:
      let x = 10;
      function test() {
          let x = 20;
          console.log(x);
      }
      test();
      console.log(x);
  2. 호이스팅 이해
    • 다음 코드의 출력 결과를 예상하세요:
      console.log(a);
      var a = 10;
  3. 클로저 활용
    • 카운터 함수를 만들어서 호출할 때마다 숫자가 증가하도록 하세요.
  4. 스코프 체인
    • 3단계 중첩 함수를 만들고, 각 레벨의 변수에 접근하는 코드를 작성하세요.

다음 장 예고

다음 장에서는 실습 문제를 통해 지금까지 배운 내용을 종합적으로 활용합니다.

'FrontEnd > Javascript' 카테고리의 다른 글

JavaScript DOM과 이벤트 완전 정복  (1) 2026.02.06
14장. 실습 문제  (0) 2026.01.13
12장. 이벤트 (Event)  (0) 2026.01.11
11장. DOM 조작  (0) 2026.01.10
10. 객체  (0) 2026.01.09