-
0. 자바스크립트의 스코프, 변수 선언 방식
-
1. 자바스크립트의 스코프 개념
-
2. 자바스크립트의 식별자 결정(identifier resolution)
-
⭐⭐⭐ 3. 렉시컬 환경(Lexical Environment)과 실행 컨텍스트(Execution Context), 스코프의 역할
-
4. 스코프 체인 (Scope Chain)
-
5. 함수 레벨 스코프(Function Level Scope)와 블록 레벨 스코프(Block Level Scope)
-
6. 자바스크립트의 스코프 결정 방식: 렉시컬 스코프(Lexical Scope) vs 동적 스코프(Dynamic Scope)
해당 글은 '모던 자바스크립트 Deep Dive 자바스크립트의 기본 개념과 동작 원리'를 참고 했습니다.
0. 자바스크립트의 스코프, 변수 선언 방식
자바스크립트의 스코프는 다른 언어와 차이가 있으며, 특히 var, let, const 키워드에 따라 다르게 동작한다.
- 스코프와 변수: 변수와 함수는 특정 범위(스코프) 내에서만 접근 가능하다.
- var vs let/const: var는 함수 스코프를 가지지만, let과 const는 블록 스코프를 가진다.
- 블록 스코프: {}(중괄호)로 감싸진 코드 블록 내부에서만 변수가 유효하다.
- 함수의 매개변수 스코프: 함수의 매개변수는 함수 내부에서만 접근 가능하며, 외부에서는 참조할 수 없다.
1. 자바스크립트의 스코프 개념
- 스코프(유효 범위): 변수, 함수, 클래스 등의 식별자가 유효한 범위를 의미한다.
- 스코프 결정 방식: 식별자는 선언된 위치에 따라 참조할 수 있는 범위가 결정된다.
- 적용 대상: 변수 이름, 함수 이름, 클래스 이름 등 모든 식별자가 해당된다.
2. 자바스크립트의 식별자 결정(identifier resolution)
- 식별자 결정: 같은 이름의 변수가 여러 개 존재할 때, 자바스크립트 엔진이 어떤 변수를 참조해야 할지를 결정하는 과정이다.
- 스코프의 역할: 엔진은 스코프를 기반으로 변수를 검색하여 올바른 식별자를 찾는다.
따라서, 스코프란 자바스크립트 엔진이 식별자를 검색할 때 사용하는 규칙이라고도 할 수 있다.
⭐⭐⭐ 3. 렉시컬 환경(Lexical Environment)과 실행 컨텍스트(Execution Context), 스코프의 역할
- 렉시컬 환경(Lexical Environment) = 코드가 위치한 문맥 : 코드가 어디서 실행되는지와 주변 코드가 무엇인지를 나타내는 개념. 즉, 변수나 함수가 선언된 위치는 스코프(유효 범위), 변수 참조 가능 여부, 클로저 생성 여부, 실행 컨텍스트에서의 검색 순서 등에 영향을 미친다.
function outer() {
let a = 10;
function inner() {
console.log(a); // inner 함수가 선언된 위치(렉시컬 환경)에서 a를 찾음
}
inner();
}
outer(); // 10 출력
위 코드에서 inner 함수는 outer 내부에서 선언되었으므로 outer의 변수를 접근할 수 있다. 이처럼 변수의 유효 범위는 "선언된 위치"에 의해 결정되며, 이를 렉시컬 스코핑(Lexical Scoping) 이라고 한다.
- 실행 컨텍스트(Execution Context) = 실제 실행되는 환경 : 실행 컨텍스트는 코드가 실제로 실행될 때의 환경이다. 자바스크립트 엔진은 코드를 실행하기 전에 실행 컨텍스트를 생성하고, 여기서 렉시컬 환경을 참고해서 어떤 변수를 사용할지 결정한다.
function hello() {
console.log("Hello World");
}
hello(); // 실행 컨텍스트가 생성되어 실행됨
함수가 실행될 때마다 새로운 실행 컨텍스트가 생성되어 해당 함수 내부에서 변수를 찾고 실행하는 것이다.
- 스코프와 실행 컨텍스트의 관계: 스코프는 실행 컨텍스트와 깊이 연결되어 있으며, 식별자(변수, 함수, 클래스)의 유효 범위를 결정한다.
- 스코프의 역할 = 변수 이름 충돌 방지 : 변수 이름 충돌을 방지하고, 같은 변수 이름을 여러 곳에서 사용할 수 있도록 하는 역할도 한다.
- 스코프는 네임스페이스(Namespace): 같은 스코프 내에서는 식별자가 유일해야 하지만, 다른 스코프에서는 같은 이름을 사용할 수 있다. 네임스페이스란 이름이 충돌하지 않도록 관리하는 개념이다. 스코프 덕분에 같은 이름을 가진 변수를 각기 다른 영역에서 사용 가능하다.
4. 스코프 체인 (Scope Chain)
자바스크립트에서는 함수 내부에서 또 다른 함수를 정의할 수 있으며, 이를 함수의 중첩이라고 한다. 내부에 선언된 함수를 중첩 함수(nested function), 이를 감싸는 함수를 외부 함수(outer function) 라고 한다.
함수가 중첩되면, 각각의 지역 스코프도 중첩되며, 이러한 구조는 계층적인 관계를 형성한다. 즉, 중첩 함수의 스코프는 외부 함수의 스코프를 포함하게 되며, 외부 함수의 지역 스코프는 중첩 함수의 상위 스코프가 된다. 이는 **스코프 체인(Scope Chain)**을 형성하여 내부 함수에서 상위 스코프의 변수에 접근할 수 있도록 한다.

자바스크립트에서 모든 스코프는 계층적으로 연결되며, 최상위에는 전역 스코프가 존재한다. 이러한 계층적 구조를 스코프 체인(Scope Chain) 이라고 한다. 스코프 체인은 전역 스코프를 시작으로, 함수가 중첩될 때마다 새로운 지역 스코프가 생성되어 계층을 형성한다. 하위 스코프에서는 상위 스코프의 변수에 접근할 수 있지만, 상위 스코프에서는 하위 스코프의 변수에 접근할 수 없다.
자바스크립트 엔진은 변수를 참조할 때, 먼저 해당 변수가 선언된 현재 스코프에서 찾고, 없으면 상위 스코프로 이동하여 변수를 검색하는 식별자 결정(Identifier Resolution) 과정을 거친다. 이렇게 해서 최종적으로 전역 스코프까지 변수를 찾으며, 변수가 존재하지 않으면 ReferenceError가 발생한다.
스코프 체인은 실제로 렉시컬 환경(Lexical Environment) 이라는 자료구조로 구현된다. 코드가 실행되기 전에 자바스크립트 엔진은 렉시컬 환경을 생성하고, 변수 선언 시 변수 식별자를 이 환경에 키로 등록한다. 이후 값이 할당되면 해당 키의 값이 변경되며, 변수 검색도 이 구조에서 이루어진다. 즉, 자바스크립트 엔진은 실행 전에 스코프 체인을 설정하며, 변수 검색과 할당은 이 구조를 기반으로 동작한다.
5. 함수 레벨 스코프(Function Level Scope)와 블록 레벨 스코프(Block Level Scope)
자바스크립트에서 지역(Local)이란 함수 몸체 내부를 의미하며, 함수는 자체적인 지역 스코프를 생성한다. 즉, 함수 내부에서 선언된 변수는 해당 함수 내에서만 접근할 수 있다.
대부분의 프로그래밍 언어(C, Java 등)는 if, for, while, try/catch 같은 모든 코드 블록이 지역 스코프를 생성하는데, 이를 블록 레벨 스코프(Block Level Scope) 라고 한다. 하지만 var 키워드로 선언된 변수는 코드 블록이 아닌, 오직 함수의 코드 블록(함수 몸체)에서만 지역 스코프가 생성된다. 이러한 특성을 함수 레벨 스코프(Function Level Scope) 라고 한다.
즉, 자바스크립트에서 var 키워드를 사용할 경우, 함수 내에서 선언된 변수는 해당 함수에서만 유효하지만, if문이나 for문 같은 코드 블록에서는 영향을 받지 않고 여전히 함수 스코프 내에 존재한다. 이로 인해 의도치 않은 변수의 유효 범위 확장이 발생할 수 있으므로, ⭐⭐⭐블록 레벨 스코프를 지원하는 let과 const 키워드를 사용하는 것이 바람직하다.
** var의 블록 스코프 동작
자바스크립트에서 var 키워드는 **함수 스코프(Function Scope)**를 따르며, 블록 스코프(Block Scope)를 따르지 않는다.
1. 전역에서 var x 선언 후, 블록에서 var x 선언:
var x = 10; // 전역 변수
{
var x = 20; // 블록 내부에서 var 선언
console.log(x); // 20
}
console.log(x); // 20 (전역 x가 변경됨)
➡ 블록 스코프를 무시하고, 기존의 전역 변수 x를 재할당함.
2. 블록 내부에서만 var x 선언:
{
var x = 30; // 블록 내부에서 var 선언
console.log(x); // 30
}
console.log(x); // 30 (블록을 빠져나와도 접근 가능)
➡ 여전히 블록 스코프를 무시하고 x는 전역 변수로 선언됨.
3. 결론:
✅ var는 블록 스코프를 따르지 않으며, 같은 이름의 변수를 선언하면 기존 변수를 덮어쓴다.
✅ 블록 내에서만 var x를 선언해도 전역 변수가 된다.
✅ 함수 내부에서 var를 선언하면 지역 변수(Local Variable)가 된다.
function test() {
var y = 50; // 함수 내부에서 선언된 var는 함수 스코프를 가짐
}
console.log(y); // ReferenceError: y is not defined
➡ 함수 내부에서 선언된 var는 함수 스코프를 가지므로 함수 바깥에서는 접근할 수 없다.
{
let x = 20; // 블록 스코프 변수
console.log(x); // 20
}
console.log(x); // ReferenceError: x is not defined
➡ let 또는 const를 사용하면 블록 스코프가 적용되어, 블록을 벗어나면 변수에 접근할 수 없다.
6. 자바스크립트의 스코프 결정 방식: 렉시컬 스코프(Lexical Scope) vs 동적 스코프(Dynamic Scope)
var x = 1;
function foo() {
var x = 10;
bar(); // bar()는 foo 내부에서 호출되었지만, 상위 스코프는 여전히 전역 스코프!
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
주어진 코드에서 bar 함수가 foo 내부에서 호출되었기 때문에, bar 함수가 참조하는 x의 값이 foo 함수의 지역 변수 x = 10인지, 또는 전역 변수 x = 1인지는 스코프 결정 방식에 따라 달라진다.
1. 스코프 결정 방식
✅ 동적 스코프(Dynamic Scope)
- 함수를 어디서 호출했는지에 따라 상위 스코프를 결정한다.
- bar()가 foo() 내부에서 호출되었으므로, bar의 상위 스코프는 foo의 지역 스코프가 된다.
- 이 방식이라면 console.log(x);는 foo 내부의 x = 10을 출력한다.
✅ 렉시컬 스코프(Lexical Scope, 정적 스코프(Static Scope))
- 함수를 어디서 정의했는지에 따라 상위 스코프를 결정한다.
- bar 함수는 전역에서 정의되었으므로, 상위 스코프는 항상 전역 스코프이다.
- 따라서 console.log(x);는 전역 변수 x = 1을 출력한다.
2. 자바스크립트의 스코프 결정 방식
자바스크립트는 렉시컬 스코프(Lexical Scope, 정적 스코프) 를 따른다. 즉, 함수를 어디서 호출했는지가 아니라, 어디서 정의했는지에 따라 상위 스코프가 결정된다. 따라서 bar() 함수는 전역에서 정의되었으므로, 상위 스코프는 전역 스코프가 된다.
3. 정리
- 자바스크립트는 렉시컬 스코프(Lexical Scope, 정적 스코프) 를 따른다.
- 함수의 상위 스코프는 정의된 위치를 기준으로 결정되며, 호출 위치는 영향을 주지 않는다.
- 따라서 bar 함수는 항상 전역 스코프를 참조하여 x = 1을 출력한다.
'JavaScript' 카테고리의 다른 글
[JavaScript] 커링(Currying) 이란? const fn = x => y => x + y; (0) | 2025.03.02 |
---|---|
[JavaScript] 전역 객체 프로퍼티 (0) | 2025.02.15 |
[JavaScript] Invalid left-hand side expression in prefix operation, Number( ) 함수에 연산자 적용 에러 (0) | 2025.02.06 |
[JavaScript] 자바스크립트에서 && 연산자의 동작 방식 (0) | 2025.01.30 |
[JavaScript] 변수 선언의 실행 시점과 변수 호이스팅 (0) | 2025.01.09 |
해당 글은 '모던 자바스크립트 Deep Dive 자바스크립트의 기본 개념과 동작 원리'를 참고 했습니다.
0. 자바스크립트의 스코프, 변수 선언 방식
자바스크립트의 스코프는 다른 언어와 차이가 있으며, 특히 var, let, const 키워드에 따라 다르게 동작한다.
- 스코프와 변수: 변수와 함수는 특정 범위(스코프) 내에서만 접근 가능하다.
- var vs let/const: var는 함수 스코프를 가지지만, let과 const는 블록 스코프를 가진다.
- 블록 스코프: {}(중괄호)로 감싸진 코드 블록 내부에서만 변수가 유효하다.
- 함수의 매개변수 스코프: 함수의 매개변수는 함수 내부에서만 접근 가능하며, 외부에서는 참조할 수 없다.
1. 자바스크립트의 스코프 개념
- 스코프(유효 범위): 변수, 함수, 클래스 등의 식별자가 유효한 범위를 의미한다.
- 스코프 결정 방식: 식별자는 선언된 위치에 따라 참조할 수 있는 범위가 결정된다.
- 적용 대상: 변수 이름, 함수 이름, 클래스 이름 등 모든 식별자가 해당된다.
2. 자바스크립트의 식별자 결정(identifier resolution)
- 식별자 결정: 같은 이름의 변수가 여러 개 존재할 때, 자바스크립트 엔진이 어떤 변수를 참조해야 할지를 결정하는 과정이다.
- 스코프의 역할: 엔진은 스코프를 기반으로 변수를 검색하여 올바른 식별자를 찾는다.
따라서, 스코프란 자바스크립트 엔진이 식별자를 검색할 때 사용하는 규칙이라고도 할 수 있다.
⭐⭐⭐ 3. 렉시컬 환경(Lexical Environment)과 실행 컨텍스트(Execution Context), 스코프의 역할
- 렉시컬 환경(Lexical Environment) = 코드가 위치한 문맥 : 코드가 어디서 실행되는지와 주변 코드가 무엇인지를 나타내는 개념. 즉, 변수나 함수가 선언된 위치는 스코프(유효 범위), 변수 참조 가능 여부, 클로저 생성 여부, 실행 컨텍스트에서의 검색 순서 등에 영향을 미친다.
function outer() {
let a = 10;
function inner() {
console.log(a); // inner 함수가 선언된 위치(렉시컬 환경)에서 a를 찾음
}
inner();
}
outer(); // 10 출력
위 코드에서 inner 함수는 outer 내부에서 선언되었으므로 outer의 변수를 접근할 수 있다. 이처럼 변수의 유효 범위는 "선언된 위치"에 의해 결정되며, 이를 렉시컬 스코핑(Lexical Scoping) 이라고 한다.
- 실행 컨텍스트(Execution Context) = 실제 실행되는 환경 : 실행 컨텍스트는 코드가 실제로 실행될 때의 환경이다. 자바스크립트 엔진은 코드를 실행하기 전에 실행 컨텍스트를 생성하고, 여기서 렉시컬 환경을 참고해서 어떤 변수를 사용할지 결정한다.
function hello() {
console.log("Hello World");
}
hello(); // 실행 컨텍스트가 생성되어 실행됨
함수가 실행될 때마다 새로운 실행 컨텍스트가 생성되어 해당 함수 내부에서 변수를 찾고 실행하는 것이다.
- 스코프와 실행 컨텍스트의 관계: 스코프는 실행 컨텍스트와 깊이 연결되어 있으며, 식별자(변수, 함수, 클래스)의 유효 범위를 결정한다.
- 스코프의 역할 = 변수 이름 충돌 방지 : 변수 이름 충돌을 방지하고, 같은 변수 이름을 여러 곳에서 사용할 수 있도록 하는 역할도 한다.
- 스코프는 네임스페이스(Namespace): 같은 스코프 내에서는 식별자가 유일해야 하지만, 다른 스코프에서는 같은 이름을 사용할 수 있다. 네임스페이스란 이름이 충돌하지 않도록 관리하는 개념이다. 스코프 덕분에 같은 이름을 가진 변수를 각기 다른 영역에서 사용 가능하다.
4. 스코프 체인 (Scope Chain)
자바스크립트에서는 함수 내부에서 또 다른 함수를 정의할 수 있으며, 이를 함수의 중첩이라고 한다. 내부에 선언된 함수를 중첩 함수(nested function), 이를 감싸는 함수를 외부 함수(outer function) 라고 한다.
함수가 중첩되면, 각각의 지역 스코프도 중첩되며, 이러한 구조는 계층적인 관계를 형성한다. 즉, 중첩 함수의 스코프는 외부 함수의 스코프를 포함하게 되며, 외부 함수의 지역 스코프는 중첩 함수의 상위 스코프가 된다. 이는 **스코프 체인(Scope Chain)**을 형성하여 내부 함수에서 상위 스코프의 변수에 접근할 수 있도록 한다.

자바스크립트에서 모든 스코프는 계층적으로 연결되며, 최상위에는 전역 스코프가 존재한다. 이러한 계층적 구조를 스코프 체인(Scope Chain) 이라고 한다. 스코프 체인은 전역 스코프를 시작으로, 함수가 중첩될 때마다 새로운 지역 스코프가 생성되어 계층을 형성한다. 하위 스코프에서는 상위 스코프의 변수에 접근할 수 있지만, 상위 스코프에서는 하위 스코프의 변수에 접근할 수 없다.
자바스크립트 엔진은 변수를 참조할 때, 먼저 해당 변수가 선언된 현재 스코프에서 찾고, 없으면 상위 스코프로 이동하여 변수를 검색하는 식별자 결정(Identifier Resolution) 과정을 거친다. 이렇게 해서 최종적으로 전역 스코프까지 변수를 찾으며, 변수가 존재하지 않으면 ReferenceError가 발생한다.
스코프 체인은 실제로 렉시컬 환경(Lexical Environment) 이라는 자료구조로 구현된다. 코드가 실행되기 전에 자바스크립트 엔진은 렉시컬 환경을 생성하고, 변수 선언 시 변수 식별자를 이 환경에 키로 등록한다. 이후 값이 할당되면 해당 키의 값이 변경되며, 변수 검색도 이 구조에서 이루어진다. 즉, 자바스크립트 엔진은 실행 전에 스코프 체인을 설정하며, 변수 검색과 할당은 이 구조를 기반으로 동작한다.
5. 함수 레벨 스코프(Function Level Scope)와 블록 레벨 스코프(Block Level Scope)
자바스크립트에서 지역(Local)이란 함수 몸체 내부를 의미하며, 함수는 자체적인 지역 스코프를 생성한다. 즉, 함수 내부에서 선언된 변수는 해당 함수 내에서만 접근할 수 있다.
대부분의 프로그래밍 언어(C, Java 등)는 if, for, while, try/catch 같은 모든 코드 블록이 지역 스코프를 생성하는데, 이를 블록 레벨 스코프(Block Level Scope) 라고 한다. 하지만 var 키워드로 선언된 변수는 코드 블록이 아닌, 오직 함수의 코드 블록(함수 몸체)에서만 지역 스코프가 생성된다. 이러한 특성을 함수 레벨 스코프(Function Level Scope) 라고 한다.
즉, 자바스크립트에서 var 키워드를 사용할 경우, 함수 내에서 선언된 변수는 해당 함수에서만 유효하지만, if문이나 for문 같은 코드 블록에서는 영향을 받지 않고 여전히 함수 스코프 내에 존재한다. 이로 인해 의도치 않은 변수의 유효 범위 확장이 발생할 수 있으므로, ⭐⭐⭐블록 레벨 스코프를 지원하는 let과 const 키워드를 사용하는 것이 바람직하다.
** var의 블록 스코프 동작
자바스크립트에서 var 키워드는 **함수 스코프(Function Scope)**를 따르며, 블록 스코프(Block Scope)를 따르지 않는다.
1. 전역에서 var x 선언 후, 블록에서 var x 선언:
var x = 10; // 전역 변수
{
var x = 20; // 블록 내부에서 var 선언
console.log(x); // 20
}
console.log(x); // 20 (전역 x가 변경됨)
➡ 블록 스코프를 무시하고, 기존의 전역 변수 x를 재할당함.
2. 블록 내부에서만 var x 선언:
{
var x = 30; // 블록 내부에서 var 선언
console.log(x); // 30
}
console.log(x); // 30 (블록을 빠져나와도 접근 가능)
➡ 여전히 블록 스코프를 무시하고 x는 전역 변수로 선언됨.
3. 결론:
✅ var는 블록 스코프를 따르지 않으며, 같은 이름의 변수를 선언하면 기존 변수를 덮어쓴다.
✅ 블록 내에서만 var x를 선언해도 전역 변수가 된다.
✅ 함수 내부에서 var를 선언하면 지역 변수(Local Variable)가 된다.
function test() {
var y = 50; // 함수 내부에서 선언된 var는 함수 스코프를 가짐
}
console.log(y); // ReferenceError: y is not defined
➡ 함수 내부에서 선언된 var는 함수 스코프를 가지므로 함수 바깥에서는 접근할 수 없다.
{
let x = 20; // 블록 스코프 변수
console.log(x); // 20
}
console.log(x); // ReferenceError: x is not defined
➡ let 또는 const를 사용하면 블록 스코프가 적용되어, 블록을 벗어나면 변수에 접근할 수 없다.
6. 자바스크립트의 스코프 결정 방식: 렉시컬 스코프(Lexical Scope) vs 동적 스코프(Dynamic Scope)
var x = 1;
function foo() {
var x = 10;
bar(); // bar()는 foo 내부에서 호출되었지만, 상위 스코프는 여전히 전역 스코프!
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
주어진 코드에서 bar 함수가 foo 내부에서 호출되었기 때문에, bar 함수가 참조하는 x의 값이 foo 함수의 지역 변수 x = 10인지, 또는 전역 변수 x = 1인지는 스코프 결정 방식에 따라 달라진다.
1. 스코프 결정 방식
✅ 동적 스코프(Dynamic Scope)
- 함수를 어디서 호출했는지에 따라 상위 스코프를 결정한다.
- bar()가 foo() 내부에서 호출되었으므로, bar의 상위 스코프는 foo의 지역 스코프가 된다.
- 이 방식이라면 console.log(x);는 foo 내부의 x = 10을 출력한다.
✅ 렉시컬 스코프(Lexical Scope, 정적 스코프(Static Scope))
- 함수를 어디서 정의했는지에 따라 상위 스코프를 결정한다.
- bar 함수는 전역에서 정의되었으므로, 상위 스코프는 항상 전역 스코프이다.
- 따라서 console.log(x);는 전역 변수 x = 1을 출력한다.
2. 자바스크립트의 스코프 결정 방식
자바스크립트는 렉시컬 스코프(Lexical Scope, 정적 스코프) 를 따른다. 즉, 함수를 어디서 호출했는지가 아니라, 어디서 정의했는지에 따라 상위 스코프가 결정된다. 따라서 bar() 함수는 전역에서 정의되었으므로, 상위 스코프는 전역 스코프가 된다.
3. 정리
- 자바스크립트는 렉시컬 스코프(Lexical Scope, 정적 스코프) 를 따른다.
- 함수의 상위 스코프는 정의된 위치를 기준으로 결정되며, 호출 위치는 영향을 주지 않는다.
- 따라서 bar 함수는 항상 전역 스코프를 참조하여 x = 1을 출력한다.
'JavaScript' 카테고리의 다른 글
[JavaScript] 커링(Currying) 이란? const fn = x => y => x + y; (0) | 2025.03.02 |
---|---|
[JavaScript] 전역 객체 프로퍼티 (0) | 2025.02.15 |
[JavaScript] Invalid left-hand side expression in prefix operation, Number( ) 함수에 연산자 적용 에러 (0) | 2025.02.06 |
[JavaScript] 자바스크립트에서 && 연산자의 동작 방식 (0) | 2025.01.30 |
[JavaScript] 변수 선언의 실행 시점과 변수 호이스팅 (0) | 2025.01.09 |