let과 const 그리고 TDZ

JaeungE·2021년 7월 7일
0

JavaScript

목록 보기
6/16
post-thumbnail

ES5에서는 함수 단위 스코프를 사용하는 키워드 var 때문에 여러 가지 문제점이 발생했다.

그래서 ES6에서는 이러한 문제점을 해결하기 위해 letconst 두 가지 키워드를 새로 추가했는데, var 키워드에서 어떤 점이 바뀌었는지 한 번 알아보자!😉





let

let 키워드는 재할당이 필요한 변수에 주로 사용하는 키워드다. 또한, let 키워드는 var 키워드와 다르게 블록 단위 스코프를 사용한다!😮

이 말은, var 키워드를 사용해 함수 단위 스코프를 가질 경우 발생하는 많은 문제점이 해결된다는 소리다.

그렇다면 var 대신 let 키워드를 사용하면 어떤 점이 개선되는지 예제를 통해 한 번 알아보자!😆



변수의 중복 선언 불가

var 키워드는 다음과 같이 변수의 중복 선언이 가능했다.


var variable = 50;
var variable = 100;

console.log(variable); // 100

하지만 let 키워드는 식별자 이름을 중복해서 선언할 경우 에러가 발생한다.


let variable = 50;
let variable = 100; // SyntaxError: Identifier 'variable' has already been declared

console.log(variable); 

물론, 어디까지나 같은 스코프에서의 중복을 막는 것이라는 것을 명심하자!😠

아래의 코드는 정상적으로 동작한다.


let variable = 50;

let print = function(){
    let variable = 100;
    console.log(variable);
};

print(); // 100



반복문에서의 클로저

이미 클로저(Closure) 에서 설명했지만, ES5var 키워드만 있기 때문에 반복문 안에 있는 클로저는 원하는 결과가 나오지 않을 수 있다!😥


var arr = [];

for(var i = 0; i < 5; i++){
    arr[i] = (function(x){
        return function(){
            console.log(x);
        };
    })(i);
}

for(var i = 0; i < arr.length; i++){
    arr[i](); // 0 1 2 3 4
}

그래서 위의 코드와 같이 즉시 실행 함수 표현식을 이용해 새로운 스코프를 생성해야만 했었다.

하지만 let 키워드를 이용하면 블록 단위 스코프를 사용하므로, 새로운 스코프를 만들어서 함수를 감싸주지 않아도, 각 클로저가 별개의 환경을 가지게 할 수 있다!


var arr = [];

for(let i = 0; i < 5; i++){ // for 안의 변수를 let으로 선언
    arr[i] = function(){
        console.log(i);
    };
}

for(var i = 0; i < arr.length; i++){
    arr[i](); // 0 1 2 3 4
}

let 키워드를 이용해도 정상적으로 동작하고, 가독성이 훨씬 좋은 것을 볼 수 있다.🙂



호이스팅

let 혹은 const 키워드를 이용하면 호이스팅이 발생하지 않는다는데, 정말 사실일까???🤔

아래의 코드를 통해 확인해보자!


console.log('Hi~ ' + myName + '!!'); // Hi~ undefined!!
var myName = 'JaeungE';
console.log('Hi~ ' + myName + '!!'); // Hi~ JaeungE!!

var 키워드를 사용하면 다음과 같이 호이스팅이 일어나 변수에 값을 할당하기 전에도 변수에 접근이 가능하다는 것을 알 수 있다.

그렇다면 같은 코드에서 varlet으로 바꿔보자!😶


console.log('Hi~ ' + myName + '!!'); // ReferenceError: Cannot access 'myName' before initialization
let myName = 'JaeungE';
console.log('Hi~ ' + myName + '!!');

변수를 선언하기 전에 접근하니, 정말로 참조 에러를 발생시킨다!😲

하지만 정말로 호이스팅이 일어나지 않은 것은 아니고, TDZ 때문에 호이스팅이 일어나지 않은 것처럼 보이는 것이다.. 자세한 내용은 아래에서 다시 설명하도록 하고, const 키워드로 넘어가보자!😉





const

const 키워드는 상수와 같이 변하지 않는 값을 선언할 때 주로 사용한다.

const 키워드도 물론 블록 단위 스코프를 가진다. 그렇다면 let 키워드와의 차이점은 뭔지 자세히 알아보자!



재할당 불가

중복 선언만 아니라면 식별자에 값을 재할당해도 상관없는 let 키워드와 달리, const 키워드는 한 번 선언하고 값을 재할당하려고 하면 에러를 발생시킨다.


const constant = 'I\'m constant!';
constant = 'new String!'; // TypeError: Assignment to constant variable.

console.log(constant);

constant 식별자에 새로운 문자열을 할당하려고 했는데, 위와 같이 에러를 발생시킨다.
이러한 특징 때문에 const 키워드는 상수 혹은 객체에 주로 사용한다!



선언과 동시에 초기화

const 키워드는 위에서처럼 값을 재할당하려고 하면 에러를 발생시켰는데, 사실 선언과 초기화를 동시에 하지 않아도 Syntax Error를 발생시킨다. 아주 대단한 녀석이다..😑


const constant; // SyntaxError: Missing initializer in const declaration
constant = 'Hi'; 

console.log(constant);

위의 코드처럼 선언과 초기화를 분리하면 에러가 발생한다.

const는 값의 재할당도 불가능하지만, 꼭 선언과 동시에 초기화 시켜야 한다는 걸 잊지 말자!



주의점

const 키워드는 값의 재할당을 막아준다고 했다. 하지만 데이터 타입이 기본형이 아닌 참조형이라면 어떻게 될까?🙄

한 번 const 키워드를 이용해 객체를 만들어서 확인해보자!


const obj = {
    name : 'Object'
};

obj = {}; // TypeError: Assignment to constant variable.

새로운 빈 객체를 참조하도록 했는데, 역시나 에러를 발생시킨다.

그렇다면 객체 내부의 프로퍼티도 똑같이 보호되는지 확인해보자!


const obj = {
    name : 'Object'
};

obj.name = 'new Name';
console.log(obj.name); // new Name
obj.age = 14;
console.log(obj.age); // 14
delete obj.name;
console.log(obj.name); // undefined

결과를 보면 알다시피 const 키워드를 사용해도 obj 식별자가 가리키는 객체만 변경할 수 없고, 객체 내부의 프로퍼티는 변경 및 추가와 삭제까지 가능한 것을 볼 수 있다!😮

이제 letconst에 대해 알아보았으니, 위에서 넘어갔던 TDZ에 대해 자세히 알아보자!





Temporary Dead Zone(TDZ)

letconst 키워드 모두 호이스팅이 일어나지 않는다고 생각할 수 있겠지만, 아래의 코드를 한 번 살펴보도록 하자.


let num = 50;

{
    console.log(num); // ReferenceError: Cannot access 'num' before initialization
    let num = 100;
}

num 을 전역 변수로 선언하고 블록 안에서 출력하려고 했지만, Reference Error가 발생했다.
이것은 블록 안에 있는 num변수 호이스팅이 일어났기 때문인데, 이게 도대체 어떻게 된 걸까?🤔

그 이유는 letconst 키워드의 선언 및 초기화 과정에 TDZ가 존재하기 때문이다!



선언과 초기화의 분리

var 키워드를 이용하여 변수를 생성하면, 실행 컨텍스트와 스코프 체인에서 봤던 것처럼 선언과 초기화가 동시에 이루어지고, 모든 과정이 끝난 후 변수에 값을 할당한다. 이때 초기화는 undefined로 이루어진다.

하지만 letconst 키워드는 변수 선언과 초기화 과정이 분리되어있는데, 초기화는 변수선언문을 만나기 전까지 진행되지 않고 따라서 메모리도 할당되지 않는다!😨

이렇게 변수가 선언된 스코프의 시작부터 선언문을 만나기 전까지의 구간을 Temporary Dead Zone(TDZ) 이라고 부른다.

바로 이 TDZ 때문에 letconst호이스팅이 일어나지 않는다고 착각한 것이다.



결론은 ES6에서 생긴 let, const 키워드를 사용해도 호이스팅은 똑같이 발생한다.

또한 ES6부터는 var 키워드 대신 letconst의 사용을 권장하고 있으니, 익숙해지도록 하자!😉

0개의 댓글