Develop

[JavaScript] 변수선언 var, let, const 스코프의 종류 그리고 클로저(Closure)의 개념

issuemaker99 2024. 10. 16. 15:19
728x90

JavaScript에서 가장 중요한 문법 중 하나로 변수 선언과 **스코프(Scope)**에 대해 깊이 알아보는 시간을 갖겠습니다. 이 두 가지 개념은 JavaScript에서 코드를 작성할 때 매우 중요한 부분을 차지합니다. 특히, 변수 선언 방식과 스코프의 차이점을 잘 이해해야 의도치 않은 버그를 방지할 수 있습니다. 이번 글에서는 **변수 선언(var, let, const)**과 스코프의 종류, 그리고 **클로저(Closure)**의 개념까지 살펴보고, 각각의 특성을 코드 예제와 함께 자세히 설명하겠습니다.

 

1. 변수 선언: var, let, const

JavaScript에서 변수를 선언할 때 사용하는 키워드는 var, let, **const**가 있습니다. 이들은 서로 다른 동작 방식을 가지고 있어 적절한 상황에 따라 사용해야 합니다.

1.1 var 키워드

**var**는 JavaScript의 초기부터 사용된 변수 선언 방식으로, **함수 스코프(function scope)**를 따릅니다. 이는 변수가 선언된 함수 내에서만 유효하다는 의미입니다. 하지만 블록 스코프(예: if, for)를 무시하고, 변수가 호이스팅(hoisting)되기 때문에 의도치 않은 동작이 발생할 수 있습니다.

예시:

function exampleVar() {
    if (true) {
        var x = 10;
    }
    console.log(x); // 10 (블록 외부에서도 접근 가능)
}
exampleVar();

 

위 코드에서 var x는 if 블록 안에서 선언되었지만, 함수 전체에서 유효합니다. 이는 var가 블록 스코프를 무시하고, 함수 스코프만 따르기 때문입니다.

또한, var는 호이스팅에 의해 선언이 끌어올려지는 현상이 있습니다.

호이스팅 예시:

console.log(y); // undefined (변수가 선언되었지만 초기화되지 않음)
var y = 5;

 

위 코드는 var y가 호이스팅되어 변수 선언이 함수 또는 스크립트의 상단으로 끌어올려지지만, 값은 나중에 할당되기 때문에 undefined를 출력합니다.

1.2 let 키워드

**let**은 ES6(ECMAScript 2015)에서 도입된 변수 선언 방식으로, **블록 스코프(block scope)**를 따릅니다. 이는 변수가 선언된 블록 내부에서만 유효하다는 것을 의미합니다. let은 중복 선언이 불가능하고, var보다 더 안전하게 변수를 관리할 수 있습니다.

예시:

function exampleLet() {
    if (true) {
        let x = 10;
        console.log(x); // 10
    }
    console.log(x); // ReferenceError: x is not defined
}
exampleLet();

 

위 코드에서 let으로 선언된 변수 x는 if 블록 내부에서만 유효하며, 블록 외부에서 접근하려고 하면 오류가 발생합니다.

또한, let은 호이스팅이 발생하지만, **TDZ(Temporal Dead Zone)**이라는 구역에 들어가게 되어 선언 전에 접근할 수 없습니다.

TDZ 예시:

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

 

위 코드는 const로 선언된 변수 a에 새로운 값을 할당하려고 할 때 오류를 발생시킵니다. 하지만 객체나 배열의 경우 내부 값을 변경할 수 있습니다.

객체와 배열의 예시:

const obj = { name: 'John' };
obj.name = 'Doe'; // 객체 내부의 속성은 변경 가능

const arr = [1, 2, 3];
arr.push(4); // 배열 내부의 요소 추가 가능
console.log(arr); // [1, 2, 3, 4]

 

const로 선언된 객체나 배열은 참조 자체를 변경할 수 없지만, 내부의 값은 변경 가능합니다.

2. 스코프(Scope)

스코프란 변수의 유효 범위를 의미하며, 변수가 어디서 접근 가능한지를 결정합니다. JavaScript에서 스코프는 크게 전역 스코프(global scope), 함수 스코프(function scope), **블록 스코프(block scope)**로 나뉩니다.

2.1 전역 스코프(Global Scope)

전역 스코프에서 선언된 변수는 코드 어디에서나 접근할 수 있습니다. 함수 외부에서 선언된 변수가 여기에 해당됩니다.

예시:

let globalVar = 'I am global';

function exampleGlobal() {
    console.log(globalVar); // 'I am global'
}
exampleGlobal();
console.log(globalVar); // 'I am global'

 

위 코드에서 globalVar는 함수 외부에 선언되어 있으므로 전역에서 접근 가능합니다.

2.2 함수 스코프(Function Scope)

**var**로 선언된 변수는 함수 스코프를 따르며, 함수 내부에서만 접근 가능합니다. 함수 내부에 선언된 변수는 외부에서 접근할 수 없습니다.

예시:

function exampleFunctionScope() {
    var localVar = 'I am local';
    console.log(localVar); // 'I am local'
}
exampleFunctionScope();
console.log(localVar); // ReferenceError: localVar is not defined

 

위 코드에서 localVar는 함수 내부에서만 유효하므로, 함수 외부에서는 접근할 수 없습니다.

2.3 블록 스코프(Block Scope)

**let**과 **const**로 선언된 변수는 블록 스코프를 따르며, 블록({}) 내부에서만 유효합니다. 조건문, 반복문 등의 블록 내부에서 선언된 변수는 블록 외부에서 접근할 수 없습니다.

예시:

if (true) {
    let blockVar = 'I am block scoped';
    console.log(blockVar); // 'I am block scoped'
}
console.log(blockVar); // ReferenceError: blockVar is not defined

 

블록 내부에서 선언된 blockVar는 블록 외부에서 접근할 수 없습니다.

3. 클로저(Closure)

클로저는 함수가 자신이 선언된 환경을 기억하고, 외부 함수의 변수에 접근할 수 있는 개념입니다. 클로저는 JavaScript의 중요한 개념 중 하나로, 주로 캡슐화 상태 유지에 사용됩니다.

클로저 예시:

function outer() {
    let count = 0; // 외부 함수의 변수
    return function inner() { // 내부 함수가 외부 변수에 접근
        count++;
        return count;
    };
}

const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

 

위 코드에서 outer 함수는 내부에 count 변수를 가지고 있고, 내부 함수 inner는 이 count 변수에 접근합니다. outer 함수가 종료된 후에도 inner 함수는 count 값을 기억하고, 호출할 때마다 값을 증가시킵니다.

클로저는 상태를 유지하거나 데이터를 은닉하는 데 유용하게 사용됩니다.

 

LIST