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

hyewon ji·2023년 2월 17일

var의 문제점

ES5까지 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었다. 어떤 문제점이 있는지 살펴보자.

1. 변수 중복 선언 허용

변수 중복 선언이 가능하다. 중복 선언될때 초기화문이 있으면 var 키워드가 없는것처럼 동작하며, 초기화문이 없으면 무시된다.(에러가 발생하지 않음) 의도치 않게 변수 값을 변경시킬 수 있다.

var x = 1;
var y = 1;

var x = 100; // 재할당됨
var y; // 무시됨

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

2. 함수 레벨 스코프

var 키워드로 선언한 변수는 오로지 함수 코드 블록만을 지역 스코프로 인정한다. 따라서 함수 외부에서 등록한 변수는 코드 블록 내에서 선언해도 모두 전역변수가 된다.

var x = 1;

if (true) {
  var x = 10;
}

console.log(x) // 10
var i = 10;

for (var i=0; i<5; i++) {
	console.log(i);
}

console.log(i) // 5

전역변수를 남발할 가능성이 있고, 의도치 않게 전역 변수가 중복 선언될 수 있다.

3. 변수 호이스팅

var 키워드로 선언한 변수는 호이스팅에 의해 변수 선언문 이전에 참조할 수 있다. 값은 undefinde를 반환하고 에러를 발생시키진 않지만 프로그램 흐름상 맞지 않고 가독성을 떨어트리며 오류를 발생시킬 여지가 있다

console.log(x); // undefined

x = 1;

console.log(x); // 1

var x; // 선언 및 undefinde로 초기화

let 키워드

ES6에서는 var의 단점을 보완하기 위해 let과 const를 도입했다.

변수 중복 선언 금지

let 키워드로 변수를 중복 선언하면 SyntaxError가 발생한다.

var x = 1;
var x = 10;
let y = 2;
let y = 20; // SyntaxError: Identifier 'bar' has aleady been declared

블록 레벨 스코프

오직 함수의 코드 블록만을 지역 스코프로 인정해주는 var와 달리 let은 블록 레벨 스코프(함수, if 문, while 문, for 문, try/catch 문 등)을 따른다.

변수 호이스팅

let 키워드로 선언한 변수는 변수 호이스팅이 발생하지 않는 것처럼 동작한다.

변수 선언에는 '선언 단계', '초기화 단계', '할당 단계'가 있다.
var는 '선언 단계'와 '초기화 단계'가 한번에 실행되어 변수 값이 undefined로 초기화되고 할당문에 도달하면 '할당 단계'가 실행된다.

console.log(foo); // undefined

var foo;
console.log(foo); // undefined

foo = 1;
console.log(foo); // 1

let은 '선언 단계'가 먼저 실행되고, 변수 선언문에서 '초기화 단계'가 실행되며, 할당문에서 '할당 단계'가 실행된다. '선언 단계'에서 '초기화 단계'까지 변수를 참조할 수 없으며 이 구간을 일시적 사각지대라고 한다.

console.log(foo); // ReferenceError: foo is not defined (일시적 사각지대)

var foo;
console.log(foo); // undefined

foo = 1;
console.log(foo); // 1

이처럼 자바스크립트는 ES6에 도임된 let, const를 포함해 모든 선언(var, let, const, function, function*, class 등)을 호이스팅하지만, let, const, class를 사용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다.

전역 객체와 let의 관계

var로 선언한 전역 변수와 전역 함수, 그리고 선언하지 않은 변수(암묵적 전역)는 전역 객체의 window의 프로퍼티가 된다.

// 전역 변수
var x = 1;

//암묵적 전역
y = 2;

// 전역 함수
function foo() {};

console.log(window.x); // 1
console.log(x); // 1

console.log(window.y);
console.log(y); // 2

console.log(window.foo);
console.log(foo); // foo() {}

var과 달리, let 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다. 보이지 않는 개념적인 블록 내에 존재한다.

let x = 1;

console.log(window.x); // undefined
console.log(x); // 1

Const 키워드

const 키워드는 상수를 선언하기 위해 사용한다. let과 특징이 대부분 동일하지만 다른점이 있다.

1. 선언과 초기화

const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화를 해야한다.
let과 동일하게 블록 레벨 스코프를 가지며 변수 호이스팅이 발생하지 않는것처럼 동작한다

const foo = 1;
const bar; // SyntaxError: Missing initializer in const declaration
{
  console.log(foo) // ReferenceError: Cannot access 'foo' befor initialization
  const foo = 1;
  console.log(foo); // 1
}

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

2. 재할당 금지

재할당이 자유로운 var, let 과는 달리 const 키우드로 선언한 변수는 재할당이 금지된다.

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

3. 상수

const 키워드로 선언한 변수에 원시 값을 할당할 경우, 변수값을 변경할 수 없다.
원시값은 재할당 없이 변경을 할 수 없기 때문이다.

일반적으로 상수의 이름은 스네이크 케이스와 대문자를 사용한다. (TAX_RATE)

4. Const 키워드와 객체

const 키워드로 선언한 변수에 객체 값을 할당할 경우, 변수값을 변경할 수 있다.
객체는 재할당 없이 변경할 수 있기 때문이다. 객체가 변경될 때 변수에 할당된 참조값은 변하지 않는다.

var vs. let vs. const

  1. ES6를 사용한다면 var는 사용하지 않는다.
  2. 재할당이 필요하면 let을 사용하되 변수의 스코프를 최대한 좁게 만든다.
  3. 변경되지 않을 원시값 혹은 객체는 const를 사용한다.

0개의 댓글