본문 바로가기
Frontend/JavaScript

[Javascript] var

by Rayched 2023. 7. 23.
목차
0. 개요
1. var
 ① var
 ② var로 선언한 변수의 특징
  (1). var로 선언한 변수는 함수 스코프나 전역 스코프를 가지고 있다.
  (2). var로 선언한 변수는 중복 선언이 가능하다.
  (3). var로 선언한 변수는 호이스팅이 가능하다. (호이스팅)
2. let, const
 ① let, const로 선언한 변수(상수)는 호이스팅을 지원하는가?
 ② TDZ

0. 개요

이번에는 Javascript의 변수 선언 키워드 중 하나인 var에 대한 것을 공부해봤고

공부하면서 정리한 내용을 바탕으로 Javascript 변수 선언 키워드인 var에 대해 설명해보도록 하겠다.


1. var

① var

'var'은 Javascript의 변수 선언 키워드로 오래된 변수 선언 키워드로

현재는 ES6부터 도입된 let을 통해서 변수를 선언한다.

 

오래된 변수 선언 키워드이기 때문에 var로 선언한 변수와 let으로 선언한 변수가 큰 차이가 있을 것 같지만

실제로는 그렇게까지 큰 차이가 있지는 않고 오히려 어느 정도는 유사하다고 할 수 있다.

 

'var' 기초 문법은 아래와 같다.

var a = 1;
//var '변수 명' = '변수 값';

② var로 선언한 변수의 특징

현재 var을 사용하지 않는 이유에 대해 말하기 전에, var로 선언한 변수가 가지는 특징에 대해 알아야 한다.

var로 선언한 변수가 가지는 특징에 대해 정리하자면 다음과 같이 정리할 수 있다.

1. var로 선언한 변수는 함수 스코프나 전역 스코프를 가지고 있다.
2. var로 선언한 변수는 중복 선언이 가능하다.
3. var로 선언한 변수의 호이스팅이 가능하다.

(1). var로 선언한 변수는 함수 스코프나 전역 스코프를 가지고 있다.

var로 선언한 변수는 함수 스코프 혹은 전역 스코프를 가지게 된다.

함수 내부에서 선언한 var 변수는 함수 스코프를 가진 지역 변수로, 변수를 선언한 위치에서만 접근할 수 있다.

아래 예제를 통해서 확인해 보자.

//var 변수 (함수 내부에서 선언)

function test(){
    var A = "Hello";
    console.log(A);
}

test();
console.log(A); //error

test() 함수 외부에서 변수 A로 접근할 수 없는 것을 확인할 수 있다.

test() 함수 내부에서 선언한 var 변수 A는 함수 스코프를 가진 지역 변수이기 때문에

해당 변수를 선언했던 함수 외부에서 접근할 수 없는 것을 위의 예제 실행 결과를 통해서 확인할 수 있다.


var 변수를 if, while, for 문에서 선언했을 때, 해당 변수는 전역 스코프(Global Scope)를 가진 전역 변수가 된다.

즉, 블록({ })을 기준으로 블록 스코프가 생기지 않는다는 것으로 해당 변수를 선언한 블록 외부에서 접근할 수 있다.

//var 변수 (for 문 내부에서 선언)

let num = 3;

for (let dan = 1; dan <= 6; dan++){
    var ans = num * dan;
    console.log(`${num} * ${dan} = ${num * dan}`);
}

console.log(ans); //18

for 문 내부에서 선언한 var 변수에 접근할 수 있는 것을 확인할 수 있다.

기본적으로 블록({ }) 내부에서 선언한 변수는 블록 스코프를 가지게 되지만

var로 선언한 변수는 블록 스코프에 종속되지 않는, 전역 스코프(Global Scope)를 가진 전역 변수가 된다.

이는 위의 예제 실행 결과에서 블록 외부에서 var 변수 'ans'에 접근할 수 있는 것을 통해서 확인할 수 있다.


(2). var로 선언한 변수는 중복 선언이 가능하다.

프로그래밍 공부를 해본 적이 있다면 기본적으로 변수 이름이 중복되선 안된다는 것을 알고 있을 것이다.

Javascript에서도 let, const로 선언한 변수 및 상수는 중복 선언할 수 없다. (값의 변경은 가능)

하지만 var로 선언한 변수는 중복 선언이 가능하다.

//변수 선언 예제 (let로 선언)

let A = 10;
let A = "Number"; //error
//변수 선언 규칙에 따르면 변수의 이름은 고유해야 한다.
//앞에서 'A'라는 이름의 변수를 정의해둔 상태이기 때문에
//같은 이름으로 변수를 선언하려고 하면 error가 발생한다.

A = "Number"; //값의 재할당은 가능하다.

console.log(A);

 

//변수 선언 예제 (var로 선언)

var A = 10;
var A = "Number";

console.log(A);

var 변수 중복선언 예제 실행 결과

var로 선언한 변수는 중복 선언이 되는 것을 위의 예제 실행 결과를 통해서 확인할 수 있다.

물론 진짜로 중복 선언이 되는 것은 아니고 그렇게 보이는 것일 뿐이다.

 

실제로 위의 예제 소스코드를 실행했을 때, 해당 코드를 해석하는 자바 스크립트 엔진에서

아래와 같은 형식으로 변환해서 해석했기 때문에 위와 같은 결과가 나오게 되는 것이다.

//변수 선언 예제 (var 변수)

//Before
var A = 10;
var A = "Number";

console.log(A);

//After
var A = 10;
A = "Number";

console.log(A);

(3). var로 선언한 변수의 호이스팅이 가능하다.

var로 선언한 변수는 호이스팅이 지원된다. 여기서 호이스팅이란 무엇일까?

아래에 예제 소스코드를 하나 준비해 놨다. 해당 소스코드를 복사해서 개발자 콘솔에서 실행해 보자.

print();

function print(){
	console.log("Hello");
}

실행 결과를 확인해 보면 먼저 print 함수를 실행하는 명령을 작성하고

그다음에 바로 아래 줄에서 선언한 print 함수를 끌어와서 사용한 것처럼 보인다.

이런 식으로 아직 선언되지 않은 변수나 함수를 끌어와서 사용하는 기능호이스팅(Hoisting)이라고 한다.

 

//var 변수의 호이스팅

console.log(a); //?

var a = 10;

방금 전의 함수의 호이스팅과는 사뭇 다른 결과가 나온 것을 확인할 수 있을 것이다.

일단 undefined가 출력된 것으로 봐서 코드 상으로는 문제가 없는 것을 알 수 있다.

하지만 왜 이러한 결과가 나온 것일까?

 

그것은 변수 a의 값을 console에 출력하는 시점에서

변수의 선언과 초기화까지는 완료됐지만 원하는 값을 할당하는 단계까지는 가지 않았기 때문이다.

//var 변수 호이스팅

//before
console.log(a);

var a = 10;

//after
var a = undefined;
console.log(a); //undefined
a = 10;

기본적으로 모든 프로그램은 절차지향, 작성한 순서대로 실행된다.

코드를 작성할 때 변수나 함수를 먼저 실행하고, 그 후에 선언하는 호이스팅의 형식으로 작성을 했다고 해도

실제로 프로그램을 실행할 때 해당 소스코드들은 위의 예제의 after와 같은 형식으로 변환돼서 실행된다.

 

이를 기반으로 예제가 실행된 과정을 정리하면 아래와 같이 정리를 할 수 있다.

1. var 변수 a를 선언하고, 해당 변수를 undefined라는 값을 할당한다. (변수 초기화)
2. 변수 a에 저장된 값을 출력한다. 이때 변수 a는 undefined라는 값을 할당받은 상태이므로
     console 창에 변수 a의 현재 값인 undefined라는 값을 출력하게 된다.
3. 이후에 변수 a에 원하는 값, 숫자 10을 저장한다.

2. let, const

① let, const로 선언한 변수(상수)는 호이스팅을 지원하는가?

앞에서 var로 선언한 변수가 호이스팅이 된다는 것을 알았으니

이제 let, const로 선언한 변수(상수)가 호이스팅이 되는 지를 확인해 보자.

 

일단 결론부터 말하자면 let, const도 호이스팅이 가능하다.

다만, var과는 다른 결과가 나오게 된다.

//var, let, const 변수(상수) 호이스팅

console.log(age); //undefined
var age = 20;

console.log(name); // => ?
let name = "Dan";

console.log(gender); // => ?
const gender = "Male";

변수 name과 상수 gender에서 Reference Error가 발생하는 것을 확인할 수 있다.

var 변수가 undefined가 출력되지만, let과 const는 Reference Error, 참조 에러가 발생하였다.

변수 name, 상수 gender가 정의되지 않았기 때문에 참조할 수 없다는 의미이다.

앞에서 let, const도 호이스팅이 가능하다고 했었는데 왜 이러한 결과가 나왔을까?

그것은 let, const가 TDZ의 영향을 받기 때문에 이러한 결과가 나오게 된 것이다.

 


② TDZ

TDZTemporal Dead Zone의 약어로 일시적인 사각지대로 변수가 선언되고, 초기화되기 전 사이의 구간을 말한다.

TDZ에 존재하는 변수는 초기화되기 전까지 사용할 수 없다.

왜 사용할 수 없는지 알기 위해서는 Javascript의 변수 생성 과정을 알고 넘어가야 한다.

기본적으로  Javascript에서 변수를 생성하면 아래의 과정을 거치게 된다.

 

(1). 변수 선언
메모리에 값을 저장할 공간을 확보하고, 값을 저장한 공간을 식별하기 위해서
변수의 이름을 설정하는 과정을 진행하는 단계이다.

(2). 변수 초기화
값을 저장할 공간을 확보한 후에, 해당 변수(메모리 공간)에 'undefined'라는 값을 할당한다.
(변수를 'undefined' 값으로 초기화한다.)


(3). 변수에 값 할당
변수 초기화를 마치고, undefined라는 값이 저장된 변수에 원하는 값을 저장한다.

이를 바탕으로 앞에서 제시했던 예제 소스코드를 다시 확인해 보자.

//var, let, const 변수(상수) 호이스팅

console.log(age); //undefined
var age = 20;

console.log(name); // => Reference Error
let name = "Dan";

console.log(gender); // => Reference Error
const gender = "Male";

위의 소스코드를 실행했을 때 var은 undefined라는 값을 출력하고 let, const는 Reference Error가 발생하게 된다.

기본적으로 변수를 생성할 때 '변수 선언' → '변수 초기화' → '변수에 값 할당' 과정을 거치지만

var로 선언한 변수는 '변수 선언'과 '변수 초기화'가 동시에 이루어진다.

즉, age라는 변수가 선언되고, 값이 undefined로 할당, 초기화가 동시에 이뤄지므로

TDZ의 영향을 받지 않고, 해당 변수를 호이스팅 했을 때 undefined라는 값이 출력될 수 있는 것이다.

 

하지만 let, const는 '변수 선언' → '변수 초기화' → '변수에 값 할당' 과정을 순차적으로 거친다.

name, gender라는 변수(상수)를 선언했지만, undefined라는 값을 할당받지 않았기 때문에 (초기화 X)

TDZ의 영향을 받게 되어 값을 초기화하기 전까지 해당 변수(상수)를 참조할 수 없게 된다.

이를 바탕으로 정리하자면 let 변수와 const 상수를 호이스팅을 시도하려고 하면

해당 let, const 변수(상수)는 초기화가 되지 않은 상태이므로 일시적인 사각지대인 TDZ의 영향을 받으며

let 변수와 const 상수를 참조하려고 해도 초기화 전까지 사용할 수 없어서 Reference Error가 발생하게 된다.


 

참고한 문헌

웹 프론트엔드를 위한 자바스크립트 첫 걸음 (인프런)
모던 Javascript - 오래된 var
MDN Javascript - var
TDZ(Temporal Dead Zone)이란? (티스토리 우주개발자님의 블로그)