콘텐츠
변수란?
JavaScript 기초 중 변수 는 문법과 자료형 – JavaScript | MDN (mozilla.org) 사이트에 잘 정리되어 있습니다. 기본적으로 변수를 선언 할 때 var 키워드를 통해 생성을 하며 ES6 이후 엔 let, const 와 같은 키워드를 통해 변수를 선언할 수 있게 되었죠.
일단 JavaSciprt 의 변수에 대해 알아보기 전 변수의 대한 개념이 잡혀있지 않을 수도 있어 한번 변수란 무엇인가? 도 정리해 보았습니다.
변수는 영어론 variable 이라 하며 프로그래밍을 할 때 데이터를 저장하고 참조하는데 사용할 수 있도록 이름을 지정해 주는 것을 말합니다.
예를 들면 사과, 바나나, 멜론 등의 과일 값을 저장해 두고 꺼내 쓰기 위한 fruit 변수 선언을 할 수 있습니다.
한글로 ‘변수’ 라 불리 우는 이유는 말 그대로 값이 변화 하기 때문에 지어진 용어입니다. fruit 변수 안엔 코드의 흐름에 따라 위에 언급한 값을 외에도 수박으로 바뀔 수도 있습니다.
var 키워드를 이용한 변수 선언
자 이제 가장 기본적인 JavaScript 변수 선언 키워드인 var 로 변수를 선언해 보겠습니다.
선언 방법은 너무 간단합니다! 바로 var 변수명; 의 형태로 선언 됩니다.
var x = 5;
JavaScript위의 구문을 해석 하자면 변수 x 를 선언해 5라는 값을 넣은 상태 입니다.
var 키워드에는 여러 특징이 있는데 이는 다음과 같습니다.
- var 는 호이스팅 됨.
- 재선언 가능
- 재할당 가능
호이스팅
여기서 호이스팅 이란 용어가 나왔는데 이는 코드가 실제로 작성된 위치와 상관없이 가장 위로 끌어 올려지는 현상을 말합니다.
프로그래밍 코드는 기본적으로 순서대로 동작합니다. 그래서 통상적으론 var x = 5; 로 변수 x 를 선언 한 이후 이를 사용하게 되죠.
하지만 JavaScript 의 여러 코드들은 웹브라우저 에서 읽는 순간 먼저 선언 된 변수와 함수를 모두 메모리 맨 위에 올려 둔 후 코드가 동작해 이런 현상이 발생한다고 합니다.
그런데 이 x 를 위에 console.log 로 출력해 보니 undefined; 가 출력 되네요? 😯 그럼 선언이 안된 거 아닐까요? 그렇지 않습니다. 이는 변수 x 자체는 선언 되었는데 아직 값이 없는 초기화 된 상태가 표시 되는 것 입니다.
만약 호이스팅이 발생하지 않아 변수 x 가 존재하지 않았다면 콘솔 로그는 ReferenceError 를 출력 했을 겁니다.
console.log(x); // undefined 출력
var x = 5;
JavaScript호이스팅은 활용하기에 따라 메인 소스 코드만 위에 작성하고 변수, 함수 등을 하단에 몰아 작성하는 방법이 될 수 있는데 그러다 보면 어디에서 변수가 선언 되었는지 찾기 어려워져 가독성과 유지 보수에 악영향을 줍니다.
그래서 최신 키워드 들은 이 호이스팅이 실제론 발생해도 Temporal Dead Zone 라는 개념을 이용해 ReferenceError 를 발생시켜 변수 선언을 자연스럽게 먼저 하도록 유지합니다. 이에 대해선 좀 있다가 상세하게 다룰게요!
재선언/재할당
다른 프로그래밍 언어에선 이미 선언 된 변수를 재 선언 하면 오류가 발생 하지만 JavaScript는 그렇지 않습니다.
즉, 위의 코드를 하단에서 다시 var x; 로 선언 시 오류가 발생하지 않아요.
이는 JavasSript 변수 선언의 단점 입니다. 그 이유는 이 선언이 무시되고 실수로 이미 사용 중인 변수를 바꿔 버릴 수 가 있기 때문이죠.
그래서 과거 JavasSript 변수 선언 후 개발을 하다 보면 변수 명이 늘어 날 때 이런 문제가 발생하고 개발자가 검토를 잘 했어야 합니다.
코드로 동작을 설명하면 다음과 같습니다.
var x = 5;
console.log(x); // 5 출력
var x;
console.log(x); // 위에 x를 선언했어도 5가 출력
var x = 10;
console.log(x); // 10 출력
JavaScript그럼 재 할당은 무슨 의미일까요? 이는 새로운 값을 할당 할 수 있다는 이야기 입니다.
변수의 범위(scope) 함수 단위 제한 – var 키워드의 대표적인 문제점
var 키워드는 변수의 범위(scope) 가 함수 단위로 제한이 되었습니다.
이는 호이스팅과 같이 프로그래밍 중에 문제가 발생 시키기도 했는데요. 이는 만약 JavaScript 에서 if 내에서만 사용할 용도로 변수를 선언 했지만 이 변수가 {}(블록) 밖에서도 접근이 되었단 점 입니다.
다음 예시 코드를 보겠습니다.
var x = 5;
if(x === 5){
var x = 10;
}
console.log(x);
JavaScript위의 코드를 보면 if 문이나 for 문과 같은 다른 블록 내에 선언 된 변수도 같은 함수 내에선 구분 없이 선언 되고 있습니다. 이는 버그를 발생 시킬 수 있습니다.
그래서 이후 let 과 const 키워드가 등장하면서 블록 스코프로 동작하도록 변경 되었습니다.
let 과 const 키워드
위의 var 키워드를 읽어 봤으면 알겠지만 JavaScript 의 기존 변수 키워드는 여러 단점과 문제점을 가지고 있었죠?
이를 해결하고 최신 문법 트렌드를 적용한 새로운 버전인 ES6 이후 JavaScript 는 let 과 const 키워드를 지원하기 시작했습니다.
이 키워드 들은 코드 작성 시 버그를 발생 시킬 만한 요인인 호이스팅, 함수 레벨 스코프 등 JavaScript 만의 특징이 다른 프로그래밍 문법과 유사하게 동작 할 수 있도록 해결 되었습니다.
const 키워드
그중 const 키워드는 변수 키워드의 범위에서 설명 하지만 상수를 선언할 때 사용합니다. 여기서 상수란 수학적 용어와 같이 변수와 반대로 ‘변하지 않는 값’ 입니다.
예를 들어 아까 위에 var x = 5; 의 경우 이후 x = 10; 으로 값을 할당 할 수 있지만 const 로 선언할 경우 오류가 발생 합니다. 재할당이 불가능 한 것이죠.
const x = 5;
x = 10; // 오류 발생
JavaScript콘솔을 확인해 보면 Uncaught TypeError: Assignment to constant variable. 메세지가 출력 됩니다.
특이한 점은 하나 있는데 만약 const 객체(object)와 배열(Array)을 를 선언하면 속성, 키 등은 추가가 된다는 점 입니다.
이는 const가 변수에 할당된 데이터의 불변성 자체는 보장하지 않아 메모리 주소는 고정하지만 내부의 상태 변경은 허용해 발생하게 됩니다. 말이 어렵죠?
즉, 한번 선언 된 배열 상수에 새로운 값, 객체를 할당 하는 건 오류를 발생 하지만, 내부에 값을 추가 하는 건 문제가 없어요.
예시 코드를 보며 이해해 보겠습니다.
const testArray = [];
testArray.push(1); //[1] 출력
console.log(testArray);
testArray = [1,2]; //오류 발생
JavaScript참조 타입
이는 객체가 ‘참조 타입(Reference Type)’ 이여서 그렇다네요. 이는 변수에 객체가 직접 담기는 것이 아닌 객체가 저장된 메모리의 주소(참조)가 변수에 저장된다는 의미 입니다.
그래서 재할당 행위는 객체의 메모리 주소를 변경하는 행위라 오류가 발생하지만 내부의 속성이나 배열의 요소를 변경 하는 건 해당 주소에 있는 객체에 접근에 동작하여 문제가 없는 것이죠.
그러면 이로 인해 재할당 행위는 메모리 주소를 변경 시키는 것이고 const 는 이를 불가능 하게 선언하는 키워드 임을 알 수 있습니다. 👍
JavaScript 에서 참조 타입은 객체(Object), 배열(Array), 함수(Function) 등이 있습니다. 이 타입으로 선언된 const 변수는 내부의 값을 변경 가능 하다는 것이죠.
위의 배열(Array) 과 같이 객체(Object) 의 동작 예시 코드도 작성해 보겠습니다.
const obj = {a: 1};
obj.b = 2;
console.log(obj); // {a: 1, b: 2}
const obj = {a: 1, b: 2}; // 오류 발생
JavaScriptconst 키워드로 선언 된 상수 임에도 key:b, value:2 가 정상적으로 추가 되어 콘솔 에서 정상적으로 출력 됩니다.
let 키워드
let 키워드가 ES6 에서 변수를 선언하는 키워드 입니다. var 와 같이 값의 재할당이 가능하죠. 용도는 크게 차이가 없지만 프로그래밍 시 발생하는 주요한 동작 차이 점이 있어 이를 인지해야 합니다.
함수/블록 레벨 스코프
var 키워드는 함수 레벨 스코프 로 동작 함을 위에서 다루었습니다. 그리고 새로운 키워드 let(const 도 마찬가지 입니다) 키워드는 이와 다른 블록 레벨 스코프로 동작하게 됩니다.
코드로 먼저 한번 설명하면 다음과 같습니다.
if(true){
var x = 5;
}
console.log(x); //정상 출력
if(true){
let y = 5;
}
console.log(y); //오류 발생
JavaScript이처럼 let 과 const 로 선언된 변수는 같은 블록 레벨({} 범위 내에서)내에서만 이용이 가능 합니다.
재선언 불가
var 는 재선언이 가능 했지만 let / const는 에러가 발생해 콘솔에 표시 됩니다. 이는 위에 var 키워드 사용 시의 단점이 해결 되어 실수로 변수를 재선언 해 인지 하지 못한 오류가 발생하는 것을 방지해 준다고 이야기 했었습니다.
호이스팅은 되지만 사용 불가
기술적으론 let / const 로 선언된 변수도 호이스팅이 되어 메모리에 올라가지만 초기화 되지 않아요. 이게 무슨 말이냐면 var 는 선언 후 더 위에서 호출 하면 undefined; 를 출력 하고 오류를 발생하지 않는데 let / const 는 오류가 발생합니다.
Temporal Dead Zone(TDZ)
이렇게 let 과 const 를 선언 이전에 호출하면 에러를 발생 시키는 것은 TDZ 라는 새로운 개념 때문 입니다. 이런 용어가 된 것은 스코프 내에 변수가 선언 되었어도 초기화 되지 않아 접근 할 수 없는 것을 표현하기 위해 만들어졌습니다.
Temporal 은 시간적이란 의미를 지니는데 변수는 코드의 실행 시간 흐름에 따라 다른 상태를 가지는 것을 나타 냅니다.
Dead Zone 은 사각지대란 뜻으로 변수가 존재하긴 해도 아직 접근 할 수 없는 구간을 이야기 합니다.
그래서 아래에 선언 되긴 했는데 지금 순서에선 아직 접근은 못한단 의미죠.
자, 다시 돌아와서 어쨌든 TDZ 의 개념을 이해하고 좀 더 생각해 보면 호이스팅이 발생하지 않는다 라는 말 자체는 틀렸음을 알 수 있습니다.
다음 예시 코드로 좀 더 알아 보겠습니다. 이 코드는 현재 선언 되지 않는 변수를 console.log 로 출력 해보니 Uncaught ReferenceError: x is not defined. 라는 메시지가 나옵니다.
console.log(x);
JavaScript그리고 이 아래 let x = 5; 를 선언하니 Uncaught ReferenceError: Cannot access ‘x’ before initialization. 메시지가 출력 되네요. 메시지의 내용 자체가 다르죠?
console.log(x);
let x = 5;
JavaScript위의 메시지는 변수 자체가 지금 문서 내에 없다는 의미고 아래의 메시지는 변수가 존재하지만 지금 작성 중인 위치 보다 이후에 선언 되었음을 알 수 있게 됩니다.
이는 호이스팅이 발생해 메모리에 변수가 올라왔지만 아직 초기화 되지 않았음을 읽을 수 있어 발생 시킬 수 있으므로 호이스팅은 발생 하지만 이를 사용하는 것을 방지하는 let, const 의 TDZ 개념을 좀 더 쉽게 이해할 수 있습니다.
var 는 최대한 사용을 지양한다.
결론적으로 변수에 관해 읽어 봤다면 var 대신 let / const 를 사용해야 함을 알 수 있어요. var 는 내가 예기치 못한 위치에서 변수의 값이 입력 되거나 사용 될 수도 있기 때문에 큰 오류가 발생할 수 있기 때문이죠.
이는 오류가 발생해도 도대체 어디서 이 오류가 발생 했는지 추적을 하기도 어렵고 내가 실수로 이미 사용 중인 변수를 또다시 선언 할 수도 있습니다.
let 과 const 는 이런 문제들이 발생하면 바로 에러를 발생 시켜 오동작을 하지 않도록 방지하기 때문에 최신 JavaScript 프로그래머 라면 var 를 사용하지 않도록 습관을 들이는 것이 좋습니다.
물론 과거에 제작 된 라이브러리, 웹 문서는 아직 var 로 되어 있는 경우가 많으니까 이론은 알고 있어야 됩니다. var 가 아예 사라진 것이 아닌 var 를 대체 할 수 있는 새로운 키워드가 추가 된 것이니까요. 😣
오늘은 어찌 보면 프로그래밍을 시작할 때 가장 기초적이지만 중요한 부분 이였던 변수 선언에 대해 정리해 보았습니다.
저도 자연스럽게 사용하고 있었지만 왜 이런 현상이 발생 하는 지와 TDZ 와 같은 새로운 용어도 알게 되었네요.
이 글을 읽으시는 분들께서도 저와 같이 유익한 시간이 되었으면 좋겠습니다.