TIL. 54 let, const 키워드와 블록 레벨 스코프

Minjae Choi·2022년 1월 16일
0

JavaScript

목록 보기
17/20

# var 키워드(재선언, 재할당 가능)

ES5까지는 변수 선언 키워드가 var 밖에 없었다. 아래에서 var 키워드의 특징을 살펴보자.

  1. 변수 중복 선언 허용
// 변수 a를 선언했다. 그리고 이어서 아래에 다시 한 번 재선언 해보겠다. 
var a = 1;
var a = 100;
console.log(a);  // 100

// 아래 b는 선언 후 재선언 했지만, 초기화문이 없어서 var 키워드가 무시된다.
var b = 1;
var b;
console.log(b);  // 1
  • 위처럼 한 번 선언했다고 해도 무시하고 중복 선언해도 에러가 나지 않고 이후에 선언한 값으로 바뀐다.
  • 초기화문이 있는 변수 선언문은 JS 엔진에 의해 var 키워드가 없는 것처럼 동작한다.
  • 위 a 예제와 같이 같은 이름의 변수가 이미 선언되어 있는 것을 모르고 중복 선언, 할당 해버리면 의도치 않은 상황이 발생할 수 있다.

  1. 함수 레벨 스코프
// 예제 1
var a = 1;

// a는 전역 변수이고, 아래에서 중복 선언 되며 의도치 않게
// 변수값이 바뀌는 부작용이 생긴다.
if (true) {
  var a = 10;
}

console.log(a);  // 10
  • var 키워드로 선언한 변수는 오직 함수(function)의 코드 블록만을 지역 스코프로 인정한다. 따라서 함수 외부에서 var 키워드로 선언한 변수는 코드 블록 내에서 선언해도 모두 전역 변수가 된다.
// 예제 2
var a = 1;

const func = () => { var a = 10 };

console.log(a);  // 1
  • 심지어 for 문의 변수 선언문에서도 전역 변수가 되어 버린다.
var i = 10;

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

// for 문안에서만 사용하려 했지만 의도치 않게 값이 변경되었다.
console.log(i);  // 5

  1. var 키워드의 호이스팅
  • var 키워드로 변수를 선언하면 호이스팅에 의해 선언문이 스코프 선두로 끌어 올려진 것처럼 동작한다.
  • 호이스팅은 변수/함수 선언이 스코프 최상위로 끌어 올려지는 현상을 말하며 그 행위 자체를 말하는 것이 아니다.
  • 호이스팅에 의해 var 키워드로 선언한 변수는 선언문 이전에도 참조할 수 있다. 하지만 할당문 이전에 참조하면 언제나 undefined를 반환한다.
// 호이스팅에 의해 이미 a는 선언, 초기화가 진행 되었다.
console.log(a);  // undefined

a = 10;

console.log(a);  // 10

var a;
  • 위에서 말했듯이, 선언문 이전에 참조는 가능하지만 프로그램 흐름상 맞지 않고 가독성을 떨어뜨린다. 가장 중요한 것은 의도치 않은 오류를 발생시킬 여지를 남길 수 있다.

# let 키워드(재선언 불가능, 재할당 가능)

위에서 본 var 키워드의 단점을 보완하기 위해 ES6에서는 let, const 키워드를 도입했다. 아래에서 let 키워드의 특징을 살펴보겠다.

  1. 변수 중복 선언 금지
  • var 키워드와는 다르게 재선언이 되지 않는다.
let a = 1;
let a = 100;  // SyntaxError
  1. 블록 레벨 스코프
  • let 키워드로 선언한 변수는 모든 코드 블록(함수, if문, for문, while문, try/catch문 등)을 지역 스코프로 인정한다.
let a = 1;

if (true) {
  let b = 2;
}

console.log(a);  // 1
console.log(b);  // ReferenceError: b is not defined

잠깐 생각...

  • 각 지역 스코프로 인정하기 때문에 같은 변수명을 사용할 수는 있지만, 가독성이 안좋아질 수 있어 협업과 유지보수 차원에서는 변수명을 고유하게 지어주는게 좋지 않을까? (아래 예시와 같은 변수명들을 본다면 정말 힘들 것 같다...)
let i = 10;

function a = () => {
  let i = 100;

  for(let i = 0; i < 3; i++) {
    console.log(i);  // 1, 2
  }
  console.log(i);  // 100
}
console.log(i);  // 10

  1. let 키워드의 호이스팅
  • let 키워드로 변수를 선언하면 호이스팅이 일어나지 않는 것처럼 동작하지만, 실제로는 호이스팅이 일어난다.
  • let 키워드는 var 키워드와는 달리 초기화 단계가 함께 진행되지 않아 레퍼런스 에러가 난다.(선언문에 도달했을 때 초기화 진행)
  • 스코프 시작부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간을 일시적 사각지대라고 부른다.
console.log(a);  // ReferenceError
//  ---------------
//  일시적 사각지대
//  ---------------
let a;  // 초기화 진행
a = 1;  // 할당 진행
  • 자바스크립트는 ES6에서 도입된 모든 선언(let, const, var, function, function*, class)을 호이스팅 한다.

  1. 전역 객체와 let
  • var 키워드로 선언한 전역 변수, 그리고 전역 함수, 선언하지 않은 변수에 값을 할당한 암묵적 전역은 전역 객체 window의 프로퍼티가 된다.
  • 전역 객체의 프로퍼티를 참조할 때는 window를 생략할 수 있다.
var a = 1;  // 전역 변수
b = 2;  // 암묵적 전역
function c() {}  // 전역 함수

console.log(window.a);  // 1
console.log(a);  // 1 위와 같음

console.log(window.b);  // 2
console.log(b);  // 2 암묵적 전역은 전역 객체의 프로퍼티.

console.log(window.c);  // 1
console.log(c);  // 1 위와 같음
  • let 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다. window.로 접근할 수 없다.
  • let 키워드의 전역 변수는 보이지 않는 개념적인 블록 내에 존재하게 된다. (23장 “실행 컨텍스트”에서 자세히 다룬다.)
let a = 1;

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

# const 키워드(재선언 불가능, 재할당 불가능)

const 키워드는 상수를 선언하기 위해 사용한다. 하지만 반드시 상수만을 위해 사용하지는 않는다. const 키워드는 let 키워드와 대부분 동일하며 다른 점을 중심으로 살펴보겠다.

  1. 선언과 초기화
  • const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다.
const a = 1;  // 선언, 초기화 동시 진행

const a;  // 문법 에러 발생
  1. 재할당 금지
  • const 키워드로 선언한 변수는 재할당이 금지 된다.
const a = 1;
a = 2;  // 타입 에러
  1. 상수
  • const 키워드로 선언한 변수에 원시 값을 할당한 경우 변수 값을 변경할 수 없다. 원시 값은 재할당 없이 변경할 수 있는 방법이 없기 때문이다.
  • 상수는 재할당이 금지된 변수를 말한다.
let preTaxPrice = 100;  // 세전 가격
let afterTaxPrice = preTaxPrice + (PreTaxPrice * 0.1);  // 세후 가격

console.log(afterTaxPrice);  // 110
  • 위 예제에서, 0.1은 어떤 의미로 사용했는지 명확하게 알기가 어려워 가독성이 좋지 않다. 세율을 의미하는 0.1은 쉽게 바뀌지 않는 고정값이다. 이 값을 상수로 정의하면 어떠한 값인지 파악하는데 어렵지 않다.
  1. const 키워드와 객체
  • const 키워드로 선언된 변수에 객체를 할당한 경우 값을 변경할 수 있다.
  • 재할당을 금지할 뿐 불변을 의미하지는 않는다. 프로퍼티의 동적 생성, 삭제, 값의 변경을 통해 객체를 변경하는 것이 가능하다.
const a = { name: 'Lee' };

a.name = 'Choi';
console.log(a)  // { name: 'choi' }
  1. var vs let vs const
  • 변수 선언에는 기본적으로 const를 사용하고, let은 재할당이 필요한 경우에 한정해 사용하는 것이 좋다.(의도치 않은 재할당 방지)
  • 권장 규칙
    • ES6를 사용한다면 var 키워드는 지양한다.
    • 재할당 필요한 경우에만 let 키워드를 사용, 스코프는 최대한 좁게
    • 읽기 전용이나 변하지 않는 값은 const 키워드 사용
  • 변수를 선언할 때, 일단 const 키워드를 사용한 후 이후에 재할당이 필요하다면 let 키워드로 변경해도 늦지 않다.

0개의 댓글