[모던 자바스크립트 Deep Dive] 15. let, const 키워드와 블록 레벨 스코프

3 minute read

모던 딥다이브

🎉 let, const 키워드와 블록 레벨 스코프

😉 var 키워드로 선언한 변수의 문제점

🐱‍🐉 변수 중복 선언 허용

선언한 변수에 같은 스코프 내에서 중복 선언이 허용되어 변수값이 변화된다.

var x = 1;
var y = 1;

//var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언을 허용한다.
//초기화문이 있는 변수 선언문은 자바스크립트 엔진에 의해 var키워드가 없는 것 처럼 동작한다.
var x = 100; //이 곳에서 x에 100이 재할당됨

//초기화문이 없는 변수 선언문은 무시된다.
var y;

console.log(x); //100
console.lgo(y); //1

동일한 이름의 변수가 이미 선언되어 있는 것을 모르고 변수를 중복 선언하면서 값까지 할당했다면 의도치 않게 먼저 선언된 변수 값이 변경되는 부작용이 발생한다.

🐱‍🐉 함수 레벨 스코프

var키워드는 오로지 함수의 코드 블록만을 지역 스코프로 인정해 if문, for문과 같은 블록 스코프로 이루어진 문에서는 전역 변수로 작용해 의도치 않게 중복 선언되는 일이 발생한다.

var x = 1;

if (true) {
  //x는 전역 변수이다.
  //이미 선언된 전역 변수 x가 있으므로 x 변수느느 중복 선언된다.
  //이는 의도치 않게 변수값이 변경되는 부작용이 발생한다.
  var x = 10; //x값이 변경되었다.
}

console.log(x); //10

🐱‍🐉 변수 호이스팅

변수 호이스팅에 의해 var키워드로 선언한 변수는 변수 선언문 이전에 참조할 수 있게 된다.

  • 변수 선언 전의 값은 undefined이다.
  • 프로그램 흐름과 맞지 않고 가독성을 떨어뜨려 오류를 발생시킬 여지가 많다.
//이 시점에서 변수 호이스팅에 의해 이미 foo변수가 선언되었다.(1.선언단계)
//변수 foo는 undefined로 초기화된다.(2.초기화 단계)
console.log(foo); //undefined

//변수에 값을 할당(3.할당 단계)
foo = 123;

console.log(foo); //123

//변수 선언은 런타임 이전에 자바스크립트 엔제에 의해 암묵적으로 실행된다.
var foo;

위 예제는 변수 선언문이 가장 코드의 아래에 있음에도 선언문 위의 호출 명령과 할당이 가능한 것을 볼 수 있다. 이를 변수 호이스팅에 의해 나타난 결과이다.

😉 let 키워드

🐱‍🐉 변수 중복 선언 금지

let키워드로 이름이 같은 변수를 선언하면 문법에러(SyntaxError)가 발생한다.

🐱‍🐉 블록 레벨 스코프

블록 레벨 스코프 : 모든 코드 블록(함수, if문, for문, while문, try/catch 문등)을 지역 스코프로 인정한다.

let foo = 1; //전역 변수

{
  let foo = 2; //지역 변수
  let bar = 3; //지역 변수
}

console.log(foo); //1
console.log(bar); //ReferneceError : bar is not defined

함수도 코드 블록이므로 스코프를 만든다. 이때 함수 내의 코드블록은 함수 레벨 스코프에 중첩된다.

let i = 10;
function foo(){       --------------------------
  let i = 100;									| 함수 레벨 스코프
  fot(let i = 1; i<3; i++){		----			|
    console.log(i); 	/*1 2*/		|블록		|
  }									|레벨     	|
  console.log(i); 	/*100*/		---- 스코프		|
}					  --------------------------
foo();
console.log(i); //10

🐱‍🐉 변수 호이스팅

let 키워드로 선언한 변수는 ‘선언단계’와 ‘초기단계’가 분리되어 진행된다.

  • 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 실행되지만 초기화 단계는 변수 선언문에 도달할때 실행된다
console.log(foo); //ReferenceError : foo is not defined
let foo;

그래서 초기화 단계가 실행되기 이전에 변수에 접근하려고 하면 참조 에러가 발생한다.

즉, let키워드는 선언한 변수는 변수 호이스팅이 발생하지 않는 것 처럼 동작한다.
일시적 사각지대 : let키워드로 선언한 변수는 스코프의 시작 지점부터 초기화 단계시작 지점(변수 선언문)까지 변수를 참조 할 수 없는 구간.

🐱‍🐉 전역 객체와 let

let키워드로 선언한 전역 변수는 전역 객체 프로퍼티가 아님으로 window.식별자방식으로 접근 할 수 없다.
let 전역 변수는 보이지 않는 개념적인 블록(전역 렉시컬 환경의 선언전 환경 레코드)내에 존재하게 된다.

😉 const 키워드

🐱‍🐉 선언과 초기화

const키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다. -> 그렇지 않으면 문법적 오류 발생

  • let과 동일하게 블록레벨스코프르 가지며 변수 호이스팅이 일어나지 않는것 처럼 보인다.
{
  //변수 호이스팅이 발생하지 않는 것처럼 보인다.
  console.log(foo); //ReferenceError: Cannot access 'foo' before initialization
  const foo = 1;
  console.log(foo); //1
}
//블록 레벨 스코프를 갖는다.
console.log(foo); //ReferenceError: foo is not defined.

🐱‍🐉 재할당 금지

const 키워드로 선언한 변수는 재할당이 금지된다.

const foo = 1;
foo = 2; //TypeError : Assignment to constant variable.

🐱‍🐉 상수

상수는 재할당이 금지된 변수
const 키워드는 상수를 표현하는데 사용한다.

  • 상수는 상태 유지와 가독성, 유지보수의 편의를 위해 적극적으로 사용해야 한다.
  • const 키워드로 선언된 변수에 원시 값을 할당한 경우 원시 값은 변경할 수 없는 값이고 const 키워드에 의해 재할당이 금지되므로 할당된 값을 변경할 수 있는 방법은 없다.
  • 대문자로 선언해 상수임을 명확히 나타낸다.
  • 여러 단어인 경우, 언더스코어(_)로 구분해 스네이크 케이스로 표현한다.
//세율을 의미하는 0.1은 변경할 수 없는 상수로서 사용될 값이다.
//변수 이름을 대문자로 선언해 상수임을 명확히 나타낸다.
const TAX_RATE = 0.1;
//세전 가격
let preTaxPrice = 100;
//세후 가격
let afterTaxPrice = preTaxPrice + preTaxPrice * TAX_RATE;

console.log(afterTaxPrice); //110

🐱‍🐉 const키워드와 객체

const 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경 할 수 있다.

const person = {
  name: "Lee",
};
//객체는 변경 가능한 값이다. 따라서 재할당 없이 변경이 가능하다.
person.name = "Kim";

console.log(person); //{name : "Kim"}
  • 새로운 값을 재할당하는 것은 불가능하지만, 프로퍼티 동적 생성, 삭제, 프로퍼티 값의 변경을 통해 객체를 변경하는 것은 가능하다.

😉 var vs let vs const

  • 변수 선언할때에는 기본적으로 const를 사용하며
  • let은 재할당이 필요한 경우에 한정적으로 사용

  • ES6를 사용한다면 var는 사용하지 않는다.
  • 재할당이 필요한 경우에 한정해서let키워드를 사용한다. 이때 변수의 스코프는 최대한 좁게 만든다.
  • 변경이 발생하지 않고 읽기 전용으로 사용하는 (재할당이 필요없는 상수) 원시값과 객체에는 const키워드를 사용한다. const키워드는 재할당을 금지하므로 var let 키워드보다 안전하다

Leave a comment