본문으로 바로가기
반응형

 

변수(Variable)

 

자바스크립트는 데이터 타입에 유연하게 변수를 선언할 수 있다.
데이터 타입 관련 글은 여기를 참고

자바스크립트에서 변수를 선언하는 방법은 3가지(var, let, const)가 있다.

아래 표를 통해 차이점을 알아본다.

선언 예약어 var let const
중복 선언 O X X
재할당 O O X
스코프(유효범위) 함수 레벨(Function-level) 블록 레벨(Block-level) 블록 레벨(Block-level)
전역 객체 Property O X X
호이스팅(Hoisting) O O O

※ 참고 : let, const는 ES6(ES2015)부터 추가된 기능으로 var와의 차이점이 무엇인지, 왜 생겼는지를 아는 것이 중요
  - 현재, var는 사용을 권장하지 않으며, let / const만 사용하는 것이 권장된다.

 

 

① 중복 선언(Re-declare)

이미 예약어를 통해 선언한 변수를 다시 선언할 수 있는 가에 대한 부분이다.
var만 가능하며, let / const는 불가하다.

아래의 코드를 보자.

var var1 = '나는 var!';
var var1 = '중복 선언이 가능하지';

let let1 = '나는 let!';
let let1 = '중복 선언 시 에러 발생!';   // SyntaxError: Identifier 'let1' has already been declared

const con1 = '나는 const!';
const con1 = '중복 선언 시 에러 발생!'; // SyntaxError: Identifier 'con1' has already been declared

 

 

② 재할당(Update)

이미 선언된 변수에 다른 값을 다시 할당할 수 있는 가에 대한 부분이다.
var / let은 가능하며, const는 불가하다.

아래의 코드를 보자.

var var1 = '나는 var!';
var1 = '재할당 가능!';

let let1 = '나는 let!';
let1 = '재할당 가능!';

const con1 = '나는 const!';
const con1 = '재할당 시 에러 발생!'; // SyntaxError: Identifier 'con1' has already been declared

 

 

③ 스코프(Scope)

선언된 변수가 어느 범위에서 쓰일 수 있는 가에 대한 부분이다.
var는 함수 레벨 스코프이며, let / const는 블록( {} ) 레벨 스코프이다.


var
  - 함수 레벨 범위 내에서 유효
  - 함수 외부 선언 시 : Global 스코프의 전역 변수

  - 함수 내부 선언 시 : Function 스코프의 지역 변수(해당 함수 내부에서만 사용 가능)

var varGlobal = "Global 범위 var!";
console.log(varGlobal + "는 어디에서든 사용 가능!"); // Global 범위 var!는 어디에서는 사용 가능!

function temp(){
    var varFunc = "Function 범위 var!";
    console.log(varFunc + "는 함수에서만 사용 가능!"); 
}
temp(); // Function 범위 var!는 함수에서만 사용 가능!

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



if (true) {
    var varIf = "If문 내의 var!";
}
console.log(varIf + " 또한 함수 바깥이므로 외부에서 사용 가능!"); 
// If문 내의 var! 또한 함수 바깥이므로 외부에서 사용 가능!

 

let
  - 블록( {} ) 레벨 범위 내에서 유효
  - 블록 외부 선언 시 : Global 스코프의 전역 변수
  - 블록 내부 선언 시 : 블록 스코프의 지역 변수(해당 블록 내부에서만 사용 가능)

let let1 = "let1";
console.log(let1 + ", let은 전역에서 사용 가능!");


// 함수 내에서 생성된 것은 함수 내에서만 가능
function temp(){
    let let2 = "let2";
    console.log(let2 + "는 함수 블록 내에 선언되었으니 함수에서만 사용 가능!"); 
}
temp(); // Function 범위 let2는 함수에서만 사용 가능!

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



// if 블록 내에서 생성된 것은 내부에서만 가능
if (true) {
    let let3 = "let3";
}
console.log(let3); // ReferenceError: let3 is not defined

 

const
  - 블록( {} ) 레벨 범위 내에서 유효
  - 블록 외부 선언 시 : Global 스코프의 전역 변수
  - 블록 내부 선언 시 : 블록 스코프의 지역 변수(해당 블록 내부에서만 사용 가능)

const const1 = "const1";
console.log(const1 + ", const1은 전역에서 사용 가능!");


// 함수 내에서 생성된 것은 함수 내에서만 가능
function temp(){
    const const2 = "const2";
    console.log(const2 + "는 함수 블록 내에 선언되었으니 함수에서만 사용 가능!"); 
}
temp();

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



// if 블록 내에서 생성된 것은 내부에서만 가능
if (true) {
    let const3 = "const3";
}
console.log(const3); // ReferenceError: const3 is not defined

 

 

④ 전역 객체 Property

전역 객체란 전체 범위(Global Scope)에 항상 존재하는 객체를 의미한다.
자바스크립트에는 이러한 전역 객체가 있는데, 웹 브라우저에서 스크립트가 전역 변수 생성 시, 그것들은 전역 객체의 Member로 생성된다.

 

웹 브라우저(Client)의 전역 객체는 window이고, 아래의 역할을 갖는다.
  - 브라우저 F12 개발자도구 Console에서 this를 출력 시, window 객체 나오는 것을 알 수 있다.
1) 브라우저 내 모든 요소가 소속된 최상위 객체로 어디서든 접근 가능한 전역 객체(Browser, Document의 모든 객체가 포함)
2) 일반적으로 우리가 아는 브라우저의 창을 의미하며 해당 창을 제어하는 다양한 내장 객체들을 제공한다.

(참고로 서버 측(Node.js)에서는 module.exports가 전역 객체)

 

var로 선언된 변수는 전역 객체의 프로퍼티가 되고 let / const는 되지 않는다.
(이러한 사유는 자바스크립트 실행 Context의 구조와 관련이 있는데, 이와 관련해서는 별도 포스팅 진행 예정)

 

아래의 코드를 브라우저에서 F12를 눌러 console에서 테스트 해볼 수 있다.(window 객체는 브라우저의 최상위 객체이므로 VS Code 콘솔에서는 안된다.)

var var1 = "haha";  // 원시 타입
var var2 = {"test" : "test"}; // 객체 타입
console.log(window.var1); // haha
console.log(window.var2); // {test : "test"}


let let1 = "haha";  // 원시 타입
let let2 = {"test" : "test"}; // 객체 타입
console.log(window.let1); // undefined
console.log(window.let2); // undefined


const const1 = "haha";  // 원시 타입
const const2 = {"test" : "test"}; // 객체 타입
console.log(window.const1); // undefined
console.log(window.const2); // undefined

 

 

⑤ 호이스팅(Hoisting)

호이스팅은 자바스크립트의 메커니즘 중 하나로, 변수/함수의 선언 부분을 코드 실행 전에 해당 Scope 의 최상위 레벨로 이동시키는 것을 의미한다.
(주의, 할당이 아닌 선언 부분을 옮기는 것!)

일단 상단 표와 같이, var / let / const 모두 호이스팅이 되긴 하나, let과 const는 var와 차이가 있다.

 

var
  - 변수 호이스팅 발생

console.log(v); // undefined
var v = 10;

 

위 코드는 아래와 같이 번역 된다. 변수의 선언 부분이 최 상단으로 호이스트된 것을 알 수 있다.

var v;
console.log(v);
v = 10;

 

 

let / const
  - 변수 호이스팅 발생하지만 접근은 불가

console.log(l); // ReferenceError: Cannot access 'l' before initialization
let l = 10;

console.log(c); // ReferenceError: Cannot access 'c' before initialization
const c = 10;

위의 코드와 같이 접근 시 에러가 발생하는데, 내부 메커니즘이 조금 다르기 때문이다.
1) 변수 선언 후, 2) 초기화(할당)은 선언문을 실제 만났을 때 수행함.

따라서, 호이스팅은 되지만 값을 참조할 수 없어 되지 않는 것처럼 보인다.

이 때, 선언 - 초기화 사이에 참조할 수 없는 구간을 TDZ(Temporal Dead Zone)이라고 부른다.
(선언 전에 변수에 접근하는 것을 금지하는 것을 의미)

 

 

var의 문제점

 

위의 내용을 통해 알아보았듯이, var는 let / const와 일부 차이점이 있다.
그리고 그러한 내용들 때문에 var는 현재 사용이 권장되지 않는다.

 

1) 함수 레벨 스코프이다.
  - 아래 코드 처럼, v1이라는 변수를 실수로 재 선언 시, 원하지 않는 결과를 얻게 될 수 있다.
  - 반복/조건문/IIFE(즉시 실행 함수)에서 임시로 사용하던 변수가 계속 살아 있다.

var v1 = "hey";
var times = 4;

if (times > 3) {
    var v1 = "Hello"; 
}
    
console.log(v1) // "Hello"


// 아래 반복문에서 사용하는 i가 계속 살아 있게 된다.
for(var i=0; i < 5; i++){
    console.log(i);
}

 

2) 재선언이 가능하다.
  - 동일한 변수를 동일 Scope에서 재선언할 수 있어 기존 변수가 무시되는 현상이 발생할 수 있다.
  - 이 내용은 위 코드로 설명 가능(v1이 다시 만들어짐)

3) 전역 변수로 생성 시, 어디서든지 전역 객체에서 바로 접근이 가능하다.(보안 위험)

4) Hoisting(호이스팅)
  - 변수를 정의하기도 전에 사용해도 에러가 없어 직관적이지 않고 예상하지 않은 에러를 낳을 수 있다.

5) 재할당 불가한 상수를 만들 수 없다.
  - const에서는 가능한 재할당 불가한 변수를 생성하는 것이 var로는 불가하다.

// 상수로 쓰고 싶어도 불가
var PI = 3.14
PI = 123;

 

 

결론적으로, let / const를 사용해서 변수를 선언하고, 값을 재할당할 수 있는 경우가 아니면 const를 우선으로 쓰고, var는 절대로 쓰지 말 것! 을 권장한다.

반응형