본문 바로가기
Dev/🟨 JavaScript

[JavaScript] Var 예약어 - 호이스팅과 재선언 및 재할당

by 아아덕후 2022. 12. 7.
반응형
목차
Var 예약어
1. 호이스팅
2. 재선언 및 재할당
3. 함수 레벨 스코프 / ( let , const : 블록 레벨 스코프 )

var 예약어

ES6 전의 자바스크립트에서 변수를 선언하는 방법은 var 키워드 하나뿐이었다.
이에 상수를 선언하는 방법( ES6 이후부터는 const)이 없었다.
 
var예약어는 다음과 같은 특징이 있다.

  1. 호이스팅 
  2. 재선언 (몇 번이고 선언할 수 있다.)
  3. 함수 레벨 스코프

이와같은 var의 특징으로 중복 선언 및 재할당이 가능하다.
이로 인해 보다 높은 자율성은 생기지만,
문제점으로 소스코드가 복잡해질 경우 기존 선언해둔 변수를 재선언, 혹은 재할당 할 수 있기 때문에
어떤 부분에서 값이 변경되는지 파악하기 힘들어질 수 있는 큰 문제점이 있다.


1. 호이스팅

hoisting : 끌어 올린다.
상황에 따라 변수의 선언할당분리해서 선언 부분을 스코프의 가장 위쪽으로 끌어올리는 것이다.
 
 
자바스크립트 인터프리터는  함수 소스를 보고 var를 사용한 변수는 기억하고 있기 때문에
아래와 같이 “선언한 것과 같은” 효과가 나타난다.
(undefined : 선언은 되었지만 값이 할당되지 않은 상태.)

testHoisting1 = () => {
// 변수 b 선언 후 b 호출

  var a = 10;
  var b;
  console.log(`var a : ${a}`);
  console.log(`선언 b : ${b}`);
};

testHoisting2 = () => {
// b호출 후 b 선언 및 할당

  var a = 10;
  console.log(`var a : ${a}`);
  console.log(`선언 b : ${b}`);
  var b = 20;
};

testHoisting1();
testHoisting2();
              변수 b 선언 후 b 호출(testHoisting1())                        b 호출 후 b 선언 및 할당(testHoisting2())     

변수의 초기화는 코드상의 위치에 그대로 존재하지만, var를 사용한 변수는 함수의 맨 위로 끌어 올려진다.
이에 var로 선언한 변수는 함수 어디에서든 에러 없이 사용할 수 있게 된다.
 
일반적으로 코드에서 선언 되지 않은 변수가 있다면, 참조에러를 통해 에러를 출력해야 하는데
이를 호이스팅이 “선언한 것과 같은” 효과를 통해 에러를 출력하지 않으며 문제가 발생하게 된다.
 
에러 없이 사용하게 되면, 버그의 원인이 될 수 있다.
이에 에러가 나오지 않지만, 버그가 발생하여 유지 보수에 어려움을 겪게 된다.
이를 해결하기 위해  ES6 이후에서는 let을 사용하게 된다. ( 참고 : https://icea.tistory.com/49
 
[추가] let과 const에서도 호이스팅이 실행되지만, var처럼 undefined를 할당해주지 않는다.


var

testHoisting1 = () => {
  var a = 10;
  console.log(`var a : ${a}`);
  console.log(`선언 b : ${b}`);
  var b;
};
testHoisting1()
var의 경우, 선언하지 않고 출력했을 때, 정상적으로 출력되고 undefined로 지정.

let

testHoisting2 = () => {
  let a = 10;
  console.log(`let a : ${a}`);
  console.log(`선언 b : ${b}`);
  let b;
};
testHoisting2()
let의 경우, 선언하지 않고 출력했을 때, ReferenceError발생

const

testHoisting3 = () => {
  const a = 10;
  console.log(`const a : ${a}`);
  console.log(`선언 b : ${b}`);
  const b = 30;			
};
testHoisting3()
let과 마찬가지로 const의 경우, 선언하지 않고 출력했을 때, ReferenceError발생

 let 과 const는 var처럼 호이스팅은 되지만, undefined로 초기화되지 않는다
이러한 이유는 TDZ(Temporal Dead Zone)으로 인해 변수를 사용할 수 없는 일시적인 비활성 상태로 만들기 때문이다.
 


2. 재선언 및 재할당

var 예약어를 사용한 변수는 재선언 및 재할당 가능하다.
이로인해 위에서 유지해야 하는 t 값(재할당, 재선언하면 안되는 값)이
다른 위치에서 t를 재선언, 재할당하며 기존 값을 변경해 버리게 된다면, 예상치 못한 결과가 만들어 질 수 있다.
또한 함수명 변수명 같은 상태 선언 되었을 때,  변수가 함수값을 덮어쓰는 문제를 일으킬 수 있다.

testVar = () => {
  console.log(`${test} :호이스팅 `); // 호이스팅

  var test = 10;
  console.log(`${test} :선언 `); // 선언

  var test = "재선언";
  console.log(`${test} :재선언 `); // 재선언

  test = 20;
  console.log(`${test} :재할당 `); // 재할당
};

testVar();

 
 


3. 함수 레벨 스코프 ( let , const : 블록 레벨 스코프 )

 

함수 레벨 스코프

var

function testVar() {
  if (true) {
    var varVariable = "hi Var";
    console.log(`varVariable : ${varVariable}`);
  }
  console.log(`varVariable : ${varVariable}`);
}
testVar();

함수레벨스코프 var는 해당 var를 선언한 함수 내 어디서든 해당 변수를 사용할 수 있다.
 
반대로 블록레벨스코프인 let, const는 해당 변수를 선언한 블록 { } 내에서만 해당 변수를 사용할 수 있다.
(이외에 곳에서 호출 시 아래와 같이 레퍼런스에러가 발생한다!) 
 
 

블록 레벨 스코프 : let, const 

let 

function testConst() {
  if (true) {
    const constVariable = "hi Const";
    console.log(`constVariable : ${constVariable}`);
  }
  console.log(`constVariable : ${constVariable}`);
}
console.log(`constVariable : ${constVariable}`);
testConst();​

 
 

const

function testConst() {
  if (true) {
    const constVariable = "hi Const";
    console.log(`constVariable : ${constVariable}`);
  }
  console.log(`constVariable : ${constVariable}`);
}
console.log(`constVariable : ${constVariable}`);
testConst();​

 



[참고]
ES6 부터는 변수 선언을 위한 예약어로 let과 const가 추가 되며 var 예약어는 사용하지 않도록 권장되고 있다.
 
var와 let, const와 가장 큰 차이점은 스코프의 범위이다.
var는 함수 영역의 스코프를 가지며, let과 const는 블록 영역의 스코프를 가진다.

 스코프선언재할당재선언비고
var함수 영역가능가능가능호이스팅 발생, 사용 지양
let블록 영역가능가능불가능값이 바뀌는 변수
const블록 영역가능, 할당불가능불가능변하지 않는 상수 변수, 선언 시 할당 필수

 

반응형

댓글