Javascript Scope

Johnywhisky·2021년 8월 1일
0

TIL

목록 보기
5/9

Scope

자바스크립트의 변수는 선언된 위치에 따라 Scope(스코프)를 가진다. 스코프는 유효 범위라고도 하며 선언된 위치에 따라 참조 가능 여부가 나뉜다. 그리고 스코프는 총 세 개로 나눌 수 있다.

  1. Global Scope
  2. Function level Scope
  3. Block Scope

Global Scope and Function level 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에 소속되어있는 것이다.

최상위 스코프에 선언된 변수는 그 밑에 있는 스코프에서는 항상 참조할 수 있지만, 하단의 스코프에 선언된 변수는 상위 스코프에서 참조할 수 없다고 결론지을 수 있다.

Block 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문 블록 안에서 선언된 변수 xz를 블록 밖에서 참조할 때 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

Scope와 Hoisting

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가 일어난다. 물론 실제로 자바스크립트가 위 코드와 같이 작동하지는 않는다. 다만 동일한 흐름으로 정보가 처리되는 것이다.

마지막으로

자바스크립트에서 변수를 선언할 때 세 개의 타입을 지정해줄 수 있다. varlet 그리고 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)

스코프의 차이는 위에서 알아보았음으로 마지막 차이점은 다음과 같다. 먼저 varlet는 재할당(reassignment)가 가능한 반면에 const는 위 결과처럼 TypeError가 발생하며 재할당이 불가능하다는 것이다.(여기서 재할당이 불가능하다는 의미는 immutable과는 다른 의미이다.)

결론

var는 scope와 hoisting을 항상 고려하며 코드를 작성해야 하기 때문에(변동 가능성이 높음) letconst를 활용한 코딩을 지향한다고 한다. 그리고 이러한 자바스크립트의 특징을 Lexical Environment라고 한다.

profile
안녕하세요 :) 1년 차 Pythonist 백엔드 개발자 윤서준입니다.

0개의 댓글