JavaScript 변수 var에 대하여

JavaScript

문제점 😅

스크립트에 관해 구글링 하다보면 변수 선언 시 var가 아닌 let으로 시작하는 글을 종종 봤다. 내가 경험한 프로젝트 코드에서도 var를 사용하고 있고 나또한 아직도 var를 사용해왔는데, 모던 JavaScript 튜토리얼를 읽어보고 최신 스타일에 맞춰서 코딩하는 습관이 필요할 것 같아서 정리해둔다.

해결책 😏

사실상 varlet의 큰 차이는 없지만 var의 특이점은 알아둬야겠다.

var는 블록 스코프가 없다.

아주 오래전의 자바스크립트에선 블록 수준 렉시컬 환경이 만들어 지지 않았다고 한다. 그래서 var로 선언한 변수는 블록이나 루프 수준으로는 스코프1가 생기지 않기 때문에 블록 밖에서 접근 가능하다.

// test 1: if문 블록
if (true) {
  var msg1 = 'welcome!'; // 'let' 대신 'var'를 사용.
}

console.log(msg1); // welcome! (if 문이 끝났어도 변수에 여전히 접근할 수 있음)

if (false) {
  var msg2 = 'devlog!'; // 'let' 대신 'var'를 사용.
}

console.log(msg2); // undefined
// test 2: for문 블록
for (var num = 0; num < 10; num++) {
  console.log("My number is "+num); // My number is 0 ~ 9까지 log 출력.
}

alert(num); // 10, 반복문이 종료되었지만 'num'은 전역 변수이므로 여전히 접근 가능.

varif, for 등의 코드 블록을 관통한다. 그렇다면 var는 항상 전역 변수로만 사용되는 걸까?

// test 3: 함수 단위 블록
function echo() {
  if (true) {
    var say = "yaaaaaaahooooo!!!!";
  }

  alert(say); // 제대로 출력
}

echo();
alert(say); // Uncaught ReferenceError: say is not defined

var로 선언된 변수는 if블록 안에 있지만 블록 수준의 스코프가 생기지 않으므로 echo() 안에서의 alert()은 정상적으로 작동한다. 하지만 함수 블록을 벗어난 곳에서 호출 시 에러가 발생한다. 즉, 코드 블록이 함수 안에 있다면, var는 함수 레벨 변수가 된다.

let은 블록 스코프가 있다.

상기 코드를 let으로 바꿔보자.

// test 1: if문 블록
if (true) {
  let msg1 = 'welcome!'; // 'let'으로 변수를 선언함
}

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

if (false) {
  let msg2 = 'devlog!'; // 'let'으로 변수를 선언함
}

console.log(msg2); // Uncaught ReferenceError: msg2 is not defined
// test 2: for문 블록
for (let num = 0; num < 10; num++) {
  console.log("My number is "+num); // My number is 0 ~ 9까지 log 출력.
}

alert(num); // Uncaught ReferenceError: num is not defined
// test 3: 함수 단위 블록
function echo() {
  if (true) {
    let say = "yaaaaaaahooooo!!!!";
  }

  alert(say); // Uncaught ReferenceError: say is not defined
}

echo();
alert(say);

블록수준의 스코프가 생겼으므로, 좀 더 안전하게(우리가 일반적으로 알고 있는 절차로) 로직 작성을 할 수 있다.

var는 변수의 중복 선언을 허용한다.

var로 같은 변수를 여러번 중복으로 선언할 수 있다.

var user = "Pete";
var user = "John"; // 이 "var"는 아무것도 하지 않는다(이전에 이미 선언됨).
// ...에러 또한 발생하지 않는다.

alert(user); // John

그러나 동일한 코드를 let으로 바꾸면, 같은 변수를 let으로 두 번 선언했기 때문에 에러가 발생한다.

let user;
let user; // Uncaught SyntaxError: Identifier 'user' has already been declared

선언하기 전 사용할 수 있는 var 그리고 호이스팅(hoisting)

var 선언은 함수가 시작될 때 처리된다. 아래의 코드를 실행시키면 놀랍게도 실행이 잘된다.

function echo() {
  say = "yaaaaaaahooooo!!!!";

  if (false) {
    var say;
  }

  alert(say);
}
echo(); // yaaaaaaahooooo!!!!

var로 선언한 모든 변수는 함수의 최상위로 끌어 올려지는데, 이를 호이스팅(hoisting) 이라고 한다.

따라서 위의 코드는 아래 순서처럼 해석할 수 있다.

function echo() {
  var say;

  say = "yaaaaaaahooooo!!!!";

  alert(say);
}
echo(); // yaaaaaaahooooo!!!!

마무리 😎

varlet의 중요한 차이점을 알아보았다. var는 예기치 못한 프로세스상의 로직 오류를 일으킬 수 있으므로, 앞으로는 let을 사용하는 습관을 들이자. 좀 더 상세한 내용은 아래의 참고문헌 링크 참조!

참고문헌 📝

https://ko.javascript.info/var
https://ko.javascript.info/variables

  1. 스코프(Scope): 변수에 접근할 수 있는 범위, 전역(Global)과 지역(Local) 2가지 유형이 있다.