자바스크립트의 변수는 선언된 위치에 따라 Scope(스코프)를 가진다. 스코프는 유효 범위라고도 하며 선언된 위치에 따라 참조 가능 여부가 나뉜다. 그리고 스코프는 총 세 개로 나눌 수 있다.
- Global Scope
- Function level Scope
- Block Scope
var varGlobalScope = 10
function scopetest(vgs) {
var varFunctionScope = 10;
console.log(varGlobalScope)
return varFunctionScope + vgs
}
result = scopetest(varGlobalScope)
console.log(result)
console.log(varGlobalScope)
console.log(varFunctionScope)
// 결과 :
// 10
// 20
// 10
// /.~/mysql.js:49
// console.log(varFunctionScope) // Error
// ^
// ReferenceError: varFunctionScope is not defined
위 코드에서 알 수 있듯이 function 밖에서 var로 선언된 변수는 함수 내부, 외부에서 모두 코드가 인식할 수 있지만(함수 내에서 console.log
가 작동함) function 안에서 선언된 varFunctionScope
를 함수 밖에서 참조하려 할 때 에러가 발생하는 것을 알 수 있다. 이때 function block 안에서만 참조 가능한 변수는 function scope에 소속되어있고, 안과 밖에서 모두 참조 가능한 변수를 global scope에 소속되어있는 것이다.
최상위 스코프에 선언된 변수는 그 밑에 있는 스코프에서는 항상 참조할 수 있지만, 하단의 스코프에 선언된 변수는 상위 스코프에서 참조할 수 없다고 결론지을 수 있다.
블록 스코프(블록 레벨 스코프)는 자바스크립트에 존재하는 특별한 스코프이다. 블록 스코프란 코드 블록 내에서 유효한 스코프를 의미하며 자바스크립트에서 코드 블록은 중괄호({}
)로 둘러 쌓여있는 영역을 의미한다.
if (true) {
let z;
z = "Hello World"
const x = "Hello World";
console.log(x);
console.log(z);
}
// console.log(x) // Error 발생
// console.log(z) // Error 발생
if
문 블록 안에서 선언된 변수 x
와 z
를 블록 밖에서 참조할 때 ReferenceError
가 발생하는 것을 알 수 있다. 반면에 var
로 선언할 경우에는 다른 결과가 도출된다.
if (true) {
var y;
y = "Hello World"
console.log(y)
}
console.log(y)
두 번의 console.log
모두 Hello World
를 출력하는 것을 볼 수 있다. 자바스크립트에서 var
는 function level variable이기 때문에 블록 내에서 선언했더라도 전역 변수 또는 지역 변수(함수 내에서 선언됐을 경우)로 선언되기 때문이다.
var x = "World"
if (true) {
var x = "Hello"
console.log(x)
}
console.log(x)
// 결과 : Hello
// Hello
let y = "World"
if (true) {
let y = "Hello"
console.log(y)
}
console.log(y)
// 결과 : Hello
// World
Hoisting(호이스팅)은 끌어올린다는 의미의 hoist에 ing가 붙은 동명사로 변수 정보를 수집하는 과정을 이해하기 쉬운 방법으로 대체한 가상의 개념이다.
출처: 코어 자바스크립트(정재남)
즉, 변수 정보를 수집하는 과정에서 변수를 선언(declare)하는 단계를 위로 끌어올린다는 것이다. 코드로 예시를 들면 더 이해하기 쉽다.
function a (x) {
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x)
}
a(1)
// 결과 : 1
// 1
// 2
위와 같은 함수를 생각할 때 두 번째 console.log에는 undifined가 출력되어야 할 것 같은데 실제 결과는 1, 1, 2가 출력된다. 왜냐하면 hoist가 일어났기 때문이다. 위 코드가 실행되는 과정을 다시 정리하면 다음과 같다.
function a () {
var x;
var x;
var x;
x = 1;
console.log(x);
console.log(x);
x = 2;
console.log(x);
}
a(1)
var
로 선언되어있는 변수들은 declaration이 먼저 일어나고 그 이후 assignment가 일어난다. 물론 실제로 자바스크립트가 위 코드와 같이 작동하지는 않는다. 다만 동일한 흐름으로 정보가 처리되는 것이다.
자바스크립트에서 변수를 선언할 때 세 개의 타입을 지정해줄 수 있다. var
와 let
그리고 const
이다. 세 타입의 차이점은 무엇일까?
var x = 10;
console.log(x);
x = 20;
console.log(x);
const y = 10;
console.log(y);
y = 20; // TypeError: Assignment to constant variable.
console.log(y);
let z = 10;
console.log(z);
z = 20;
console.log(z)
스코프의 차이는 위에서 알아보았음으로 마지막 차이점은 다음과 같다. 먼저 var
와 let
는 재할당(reassignment)가 가능한 반면에 const
는 위 결과처럼 TypeError가 발생하며 재할당이 불가능하다는 것이다.(여기서 재할당이 불가능하다는 의미는 immutable과는 다른 의미이다.)
var
는 scope와 hoisting을 항상 고려하며 코드를 작성해야 하기 때문에(변동 가능성이 높음)let
과const
를 활용한 코딩을 지향한다고 한다. 그리고 이러한 자바스크립트의 특징을 Lexical Environment라고 한다.