변수 var, let, const 의 차이
개요
Javascript의 실행 컨텍스트에 대해 간단하게 언급하고 호이스팅을 통해 변수의 종류인 var, let, const의 차이를 이해한다.
목차
소개
1. 실행 컨텍스트(Excution Context)란?
실행 컨텍스트(Excution Context) 정의
Javascript 엔진은 코드를 실행하기 위해 필요한 몇가지 정보들을 미리 알고 있어야 한다. 그러기 위해 코드를 실행하기 전에 실행 가능한 코드들을 형상화하고 구분하는 추상적 개념이 실행 컨텍스트이다. 풀어서 설명하자면, 코드가 실행가능하기 위해 필요한 환경이라고 할 수 있다.
실행에 필요한 정보
- 변수 객체(전역변수, 지역변수, 매개변수, 객체의 프로퍼티)
- 선언된 함수
- 변수의 유효범위(Scope Chain)
- this(Default = Window)
실행 컨텍스트 생성 과정
- Javascript 엔진은 먼저 전역변수 등의 정보를 담은 전역 컨텍스트를 하나 생성 후, 함수가 호출될 때 마다 위의 정보를 담은 컨텍스트를 생성한다.
- 이러한 컨텍스트 생성 후 함수가 실행 되면 Javascript 엔진은 사용되는 변수들을 생성 된 변수 객체 내에서 먼저 찾고, 없다면 변수의 유효범위라고 할 수 있는 Scope Chain을 따라 올라가며 찾는다.
- 함수 실행이 마무리 되면 해당하는 컨텍스트는 사라지고, 전역 컨텍스트는 페이지가 끝나면 사라지게 된다.
변수 생성과 실행 컨텍스트(Excution Context)
실행 컨텍스트에 의해 Javascript 엔진은 코드를 실행하기 전에 선언된 변수들을 찾아 변수 객체에 등록해 Scope Chain에 들어가게 된다. 즉 변수는 코드가 실행되기 이전에 Javasciprt 엔진에 의해 어떠한 변수가 선언되어 있는지 알게 되는것이다. 이 때 변수는 아래와 같은 3가지 단계를 거치게 된다.
- 선언 단계(Declaration Phase): 변수를 실행 컨텍스트에 등록하여, Scope Chain 범위에 들어가게 된다.
- 초기화 단계(Initialization Phase): 변수를 위한 메모리를 할당하고, var은 변수를 undefined로 초기화한다.
- 할당 단계(Assignment Phase): 코드가 실행되어 해당 변수를 만나게 되면 해당 값으로 할당한다.
2. 호이스팅이란?
호이스팅(Hoisting)은 무엇일까?
Javascript 엔진은 코드가 실행되기 전에 실행 컨텍스트에 선언된다. 이로인해, 변수 및 함수는 코드가 실행되기 전에 변수가 어디에 선언되어 있든 먼저 실행되는 것(위로 끌어올려진 것)과 같은 현상이 발생하는 특징을 호이스팅이라고 한다.
함수와 변수가 메모리에 저장되는 방식
- 함수는 전체 함수에 대한 참조와 함께 저장된다.
- ES6 이후의 변수인 let과 const는 초기화 되지 않은 상태로 선언만(실행 컨텍스트에 등록) 이루어 지며 실제 변수 선언의 코드를 만나면 해당하는 값으로 초기화가 이루어지며 메모리에 할당되게 된다. 반면 var는 선언과 동시에 undefined로 초기화 되어 메모리에 할당된다.
3. TDZ란?
TDZ(Temporal Dead Zone)이란?
TDZ란, 위에서 언급된 실행 컨텍스트에서 Scope의 시작 지점부터 초기화가 되기 전까지의 구간을 의미한다.
4. var vs let
var vs let의 차이
var
var은 위의 왼쪽 그림처럼 선언과 동시에 undefined로 초기화가 된다.
console.log(name)
var name='SJ'
var name='JS' //변수선언의 중복을 허용하므로 에러를 일으키지 않는다.
따라서 위와 같은 코드에서 선언 되기 전에 name을 참조하게 되면 undefined로 저장되어 있는 name을 참조함에 따라, console에 undefined를 출력하게 된다.
let
let은 위의 오른쪽 그림처럼 코드에 선언된 변수를 먼저 실행 컨텍스트에 등록하여 변수를 선언한다. 그 후 var과 다르게 초기화는 하지 않기 때문에 메모리에 할당되어 있지 않고, 실제 실행 코드에서 변수를 선언하는 코드를 만나게 되면 해당하는 값으로 초기화 하게 된다.
console.log(name)
let name='SJ'
let name='JS' //변수의 중복선언이 허용되지 않아 SyntaxError를 일으킨다.
따라서 위와 같은 코드에서 선언 되기 전에 name을 참조하게 되면 let의 변수 name은 TDZ 구간에 존재해 있게 되고, 이 때는 메모리에 할당되어 있지 않아 참조에러(ReferenceError)를 일으키게 된다. 따라서 에러를 일으키지 않기 위해서는 let name='SJ' 코드를 먼저 실행시켜 name의 변수에 접근하기 전에 초기화를 먼저 해주어야 한다.
5. let vs const
let vs const의 차이
let | const | |
선언 및 초기화 | 각 단계가 분리되어 이루어진다. | 각 단계가 분리되어 이루어진다. |
변수의 중복선언 | 불가능 | 불가능 |
변수의 재할당 | 가능 | 불가능 |
스코프 유형 | *블록 레벨 스코프 | *블록 레벨 스코프 |
할당 시기 | 선언을 먼저 한 후 이후에 값을 할당해주어 된다. | 선언과 동시에 값을 할당해 주어야 한다. |
객체에 할당시 객체 안 내용 변경 허용 | O | X |
*블록 레벨 스코프 vs 함수 레벨 스코프
함수 레벨 스코프(Function-Level Scope)
함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조 할 수 없다. 따라서 함수 내부의 변수는 지역변수가 되고, 외부의 변수는 전역변수가 된다. 하지만 함수가 아닌 다른 코드블록에서 전역변수와 동일한 이름의 지역변수를 선언한다면, 해당 변수는 함수 내의 변수가 아니기 때문에 전역변수가 재할당하게 된다.
블록 레벨 스코프(Block-Level Scope)
코드 블록(함수, if문, for문, while문, try/catch문 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조 할 수 없다. 따라서 모든 코드 블록 내에서 전역변수와 같은 이름의 지역변수를 선언하여도 지역변수로 스코프가 형성되어 전역변수에 영향을 끼치지 않게 된다.
참고사이트
1. https://poiemaweb.com/es6-block-scope
2. https://poiemaweb.com/js-execution-context
'Programming Language > Javascript' 카테고리의 다른 글
[Programming Language] 스크립트 언어(Script Language) vs 컴파일 언어(Compile Language) (0) | 2021.12.25 |
---|