자바스크립트 딥다이브 - let , const , 블록 레벨 스코프

ChoiYongHyeun·2023년 12월 10일
0

이전까지 var 선언문을 통한 변수 선언에 대해 배웠다.

var 선언문을 통한 변수 선언은 여러가지 문제를 가졌다.

Var 선언문이 가지는 문제점

1. 전역 변수와 함수 레벨 스코프

함수 레벨 스코프란 함수 블록 외에 존재하는 var 은 모두 전역 변수로 취급 되고 , 함수 블록 내부에 존재하는 변수만 지역 변수로서 취급을 한다는 것이다.

전역 변수가 가지는 단점에 대해서는 이전 챕터에서 많이 공부했으니 넘어가기로 하자.

var x = 5;

if (true) {
  x = 10;
}
console.log(x); // 10

이처럼 조건문, 반복문 등에서 var 로 선언된 변수의 값을 변경하면 같은 전역 변수 스코프를 가지기 때문에 값이 변경된다.

이는 예기치 않은 값의 변경으로 문제를 가져 올 수 있다.

또한 조건문에서만 사용하고 싶은 변수가 있다고 하더라도 var 키워드는 함수를 제외하면 모두

전역 변수로 취급하기 때문에 조건문에서 사용하는 변수들 조차도 전역 변수로 생성되어

불필요한 전역 변수가 많이 생성된다는 단점이 있었다.

전역 변수는 메모리 사용량과 생명 주기가 길어 사용을 지양해야 한다.

2. 변수 재할당

1과 관련된 내용으로 var 로 선언된 변수에는 값을 재할당 하는 것이 가능하다.

이 또한 예기치 않은 값의 변경으로 문제를 가져올 수 있다.

이러한~~ 문제를 ~~~ 해결하기 위해 ~~ 나온것이 바로 let , const 선언문이다.

3. 호이스팅

var을 이용한 선언문은 가장 먼저 호이스팅 되어 값을 할당하기 전 참조하는 코드가 선행 된다고 하더라도

해당 식별자의 값을 undefined 로 먼저 참조 할 수 있었다.

이는 예기치 못한 결과 값을 나타내는 문제가 발생 할 수 있다.

아~니 나는 변수 값을 설정도 안했는데 그 변수를 사용하면 오류가 나야지 왜 undefined 가 나오냐고 ~!

let , const 선언문

let , const 객체 선언문은 기존 var 선언문이 가지던 단점을 보완한 객체 선언문이다.

두 선언문은 블록 레벨 스코프 , 선언과 초기화의 분리 라는 공통점을 갖고

차이점으로 const 는 식별자의 값을 변경하지 못한다는 차이점을 갖는다.

let선언문

블록 레벨 스코프

최대한 전역 변수의 사용을 지양해야 하기 때문에 반복문이나 , 조건문등 다양한 문 에서 사용하는 변수들도 개별적인 스코프를 가지게 하는 것이 let 선언문이다.

개별적인 스코프를 가지게 하여 전역 변수의 사용을 지양 , 적절한 메모리 사용 및 최적화를 통해 성능을 늘릴 수 있다.

for (var i = 0; i < 5; i++) {
  console.log('안녕하세요');
}

console.log(i); // 5

만약 5번 인사를 하는 반복문이 있을 때 var 키워드로 반복문 내 변수를 선언하면 반복문이 종료된 이후에도 전역 변수로 나아있는 모습을 볼 수 있다.

for (let i = 0; i < 5; i++) {
  console.log('안녕하세요');
}

console.log(i); // ReferenceError: i is not defined

하지만 let 을 사용하면 블록 레벨 스코프이기 때문에 반복문에서 선언된 i 는 반복문이 종료되며 제거된다.

이처럼 생명주기가 짧은 지역 변수를 사용 할 수 있도록 블록 레벨 스코프 를 가지게 하는 let 선언문으로 메모리를 효율적으로 사용 할 수 있다.

변수 중복 선언 금지

블록 레벨 스코프인 객체들은 스코프의 범위가 엄격하게 조절됨에 따라

같은 스코프 내에 동일한 식별자를 가진 값들이 존재하지 못하게 한다.

let hi = '안녕하세요';
let hi = '곤니찌와'; // SyntaxError: Identifier 'hi' has already been declared
var hi = '안녕하세요';
var hi = '곤니찌와';

console.log(hi); // 곤니찌와

var 키워드의 경우에는 동일한 식별자 명을 중복하여 사용하는 것이 가능했지만

let 키워드는 동일한 식별자명을 허용하지 않는다.

이는 식별자의 고유성을 높여 코드의 흐름을 추적하기 쉽게 만들 뿐 아니라 최적화도 가능하게 한다.

블록 레벨 스코프이기 때문에 다른 스코프를 가지는 곳에서는 동일한 식별자명 사용이 가능하다.

let hi = 'hi';

if (true) {
  let hi = '안녕하세요';
  console.log(hi); // 안녕하세요
}
console.log(hi); // hi

변수 호이스팅

var 키워드는 코드 어느곳에서 선언 되더라도 자바스크립트 엔진이

변수를 선언 하고 변수를 초기화 (undefined) 시켰다. (할당은 기존 코드 위치에서 시행한다.)

이는 변수를 선언하기 이전 해당 변수를 참조하려고 한다면

호이스팅 때 초기화 되어 있기 때문에 undefined 값을 참조하게 된다.

이는 변수는 사용 전에 할당해야 한다는 규칙을 어기는 것으로

예기치 못한 결과값을 가져올 수 있다.

console.log(hi);
let hi = '안녕하세요'; // ReferenceError: Cannot access 'hi' before initialization

하지만 let 선언문은 오류를 발생시킨다.

그렇다면 let 선언문은 호이스팅을 지원하지 않는 것일까 ? 그래서 hi 변수가 없는 것으로 판단하는걸까 ?

아니다.

console.log(hi); // ReferenceError: hi is not defined

선언조차 되지 않은 식별자를 로그하라고 하면 찾을 수 없다고 한다.

let 선언문은 초기화 되지 않은 식별자 hi 에는 접근할 수 없다고 한다.

let 선언문은 호이스팅 할 때 선언 만 하고 초기화 , 할당 은 코드 위치에서 시행한다.

let 선언문은 호이스팅 할 때 이런 이름을 가진 식별자가 있어요 ~ 하고 선언만 한다.

console.log(hi);
let hi = '안녕하세요'; // ReferenceError: Cannot access 'hi' before initialization

위 코드처럼 선언만 되고 , 초기화 및 할당이 이뤄지지 않은 곳에서 참조된 식별자를

일시적 사각지대 에 존재하는 식별자라고 한다.

일시적 사각지대 : 변수가 선언된 위치에서 초기화 되기 전까지의 구간

일시적 사각지대 를 생성함으로서 호이스팅에 의한 에러를 방지하고 선언과 할당 분리로 코드가 선언된 위치에서부터 사용이 가능했음이란 가독성을 높일 수 있다.

개념적인 블록

var 키워드는 전역 변수로서 브라우저 환경에선 window , 서버 환경에선 global 이란 전역 객체의 프로퍼티가 된다고 하였다.

var 뿐만 아니라 선언문 없이 실행한 것도 암묵적 전역 으로 전역 객체의 프로퍼티가 된다.

하지만 let 키워드는 전역 객체의 플퍼티가 아니라 보이지 않는 개념적인 블록 내에 존재하게 하여

전역 객체의 프로퍼티가 아닌 전역 렉시컬 환경의 선언적 환경 레코드 에 존재하게 된다.

자세한 설명은 다음에 더 공부하고 ~!!

이를 통해 변수이 범위를 명확하게 제한하고 전역 객체로 간주되어 생기는 부작용을 방지한다.

const

Const 는 위에 설명한 let 선언문과 같은 선언문이지만

차이점만 설명하자면

const 로 선언된 식별자는 값이 한 번 할당되면 변하지 않는다.

const HI = 'hi';
HI = 'hello'; // TypeError: Assignment to constant variable.

이를 통해 상태유지와 가독성, 유지보수의 편의를 위해 적극적으로 사용 할 수 있다.

한 번 할당된 값이 변화하지 않기 때문에

상수 로 선언된 식별자는 항상 선언과 할당이 동시에 이뤄져야 한다.

또한 상수임을 알기 쉽도록 대문자로 선언하거나 여러 단어로 이뤄진 경우엔 언더 스코어로 구분해서 스네이크 케이스로 표현하는 것이 일반적이다.

const 를 상속받은 객체도 변경 불가능해 ?

된다.

const HI = 'hi';

let koreaHi = HI;

koreaHi = '안녕하세요';
console.log(koreaHi); // 안녕하세요

이건 HI 의 원시값을 변경하는게 아니라 상수가 아닌 koreaHI 값을 변경하는 것이기 때문이다.

객체를 할당한 const 의 값 변경은 가능할까 ?

가능하다.

const person = {
  name: 'lee',
};

person.name = 'kim';
console.log(person);

상수인 person 이 상속받은 것은 원시값이 아닌 {} 객체이다.

객체는 값의 변경이 가능한 속성을 가지기 때문에 const 객체의 값을 변경하는 것은 가능하다.

하지만 객체 자체를 변경하는 것은 불가능하다.

const person = {
  name: 'lee',
};

person = {
  age: 18,
}; // TypeError: Assignment to constant variable.

정리

변수 선언에는 기본적으로 const 를 사용하고 재할당이 필요한 경우엔 let을 제한적으로 사용하는 것이 좋다.

다만 재할당이 필요한 경우엔 스코프를 최대한 좁게 만들기를 권장한다.

변수를 선언하는 시점에는 재할당이 필요할지 잘 모르겠지만, 생각보다 변수를 재할당 할 일이 많지 않기 때문에

일단 const 를 사용하고 재할당하게 되면 선언문만 let 으로 살짝 바꿔주자 :)

profile
빨리 가는 유일한 방법은 제대로 가는 것이다

0개의 댓글