var를 이용한 변수의 특징 / 주의점
호이스팅(hoisting)이란?
자바스크립트에서 변수를 사용할 때 조심해야 하는 개념이 있다. 바로 '호이스팅(hoisting)'이라는 개념이다.
호이스팅은 '끌어올리다'라는 의미를 가지고 있는데, 이곳에선 상황에 따라 변수의 선언과 할당을 분리해서 선언부분을 스코프의 가장 위쪽으로 끌어올리는 것을 발한다.
실제로 소스 코드가 맨 위로 올라가는 뜻이 아니라, 이런 방식으로 자바스크립트 엔진이 해석한다는 뜻이다.
예를 들어, var를 사용한 변수는 선언하기 전에 먼저 실행하고 이후에 선언하면 오류가 발생하는 것이 아니라 컴퓨터에서 임의로 undefined 값을 입력하여 값이 있는 것처럼 실행된다. 바로 호이스팅 때문이다.
이런 경우 어디에서 오류가 발생했는지 찾기 어렵다는 단점이 있기 때문에 주의해야한다.
스코프(scope)란?
스코르란 변수를 선언하고 변수가 적용되는 유효범위를 뜻한다. 변수가 쓰이는 영역을 가리키는 것이다.
자바스크립트의 함수에서 변수를 사용할 때 이 영역에 주의해야한다.
변수의 적용 범위
자바스크립트의 변수에서는 어디에서나 사용 가능한 변수와 범위가 제한되어있는 변수가 있다.
함수 안에서만 사용 가능한 변수를 '지역 변수' , 스크립트 전역에서 사용 가능한 변수를 '전역 변수' 라고 한다.
let 예약어로 선언한 변수는 선언한 범위 내에서만 유효하고 벗어나면 사용할 수 없다.
선언한 블록(함수의 중괄호 부분, for 문이나 switch문이나 함수처럼 어떤 문장 안)안에서만 유요한 것이다.
이것을 우리는 '블록 레벨의 스코프를 가진다'고 표현한다.
var 처럼 전역에서 쓰이는 변수는 '함수 레벨의 스코프를 가진다'고 표현하고 스크립트 소스 전체를 의미한다.
1. 지역 변수
지역 변수는 함수 내부에서 선언하여 함수 내부에서만 사용가능한 변수이다.
예약어 var와 함께 함수 안에서 변수를 지정하면 지역변수가 된다.
지역변수는 비유하자면 건전지와 비슷하다.
건전지는 기계 안에 들어있으면 그 기계 안에서만 사용되듯이 지역변수로 만들면 그 함수 안에서만 사용할 수 있다.
아래 예제를 보면 console.log(sum)을 실행했을 때 'sum is not defined'라는 에러 메세지가 뜨는데,
이유는 sum 이라는 변수(건전지)는 addNum함수(기계) 안에서 선언되었기 때문에 유효 범위를 벗어나서 에러 메세지가 뜨는 것이다.
2. 전역 변수
전역변수는 범위를 제한하지 않고 쓸 수 있다. 즉, 스크립트 코드 전체에서 사용할 수 있는 것이다.
변수를 전역으로 사용하고 싶을 때에는 함수 밖에서 선언하거나, var 예약어를 생략하고 선언하면 된다.
전역변수는 비유하자면 건전지가 기계 안에 있지 않고 꺼내져 있는 것이다.
집안에서 굴러다니고 있기 때문에 건전지를 내가 원하는 기계에 끼워넣어 사용할 수 있다.
<script>
// script 영역 첫째 줄부터 마지막줄까지 : 함수레벨의 스코프 또는 함수영역
for (let i = 0; i < 10; i++) {
// for 문의 첫째 줄부터 마지막줄까지 : 블록레벨의 스코프 또는 블록영역
}
</script>
// 함수 밖에서 선언하거나 키워드 없이 선언하여 전역변수 선언
var result1 = 200;
result3 = 100;
// 함수 addNum을 선언하여 내부에 지역변수 선언
function addNum() {
var sum = 10 + 20; //지역변수, sum은 addNum 안에서만 쓸 수 있다.
result2 = 300; //함수 안에 있지만, var 라는 키워드가 없기 때문에 전역변수가 된다.
}
// 선언한 함수 addNum 호출
addNum();
// sum은 전역에서 선언된 적이 없기 때문에 오류가 표시된다.
// console.log(sum);
console.log(result1); //전역변수 이기 때문에 200이 출력된다.
console.log(result2); //var를 쓰지 않았기 때문에 전역변수로 선언되어 300이 출력된다.
console.log(result3); //var를 쓰지 않았기 때문에 전역변수로 선언되어 100이 출력된다.
var num1 = 10; // num1이 선언됨
var num1 = 20; // 똑같은 이름으로 변수를 재선언
num1 = 30; // 변수에 새로운 값을 다시 넣어서 재할당
변수의 재선언 / 재할당
var를 이용한 변수는 호이스팅 이외에도 '재선언'과 '재할당'을 할 수 있다.
재선언이란, 같은 이름의 변수를 var를 붙여 여러번 선언하는 것을 말하고
재할당이란, 만들어진 변수에 값을 여러번 집어넣는 것을 말한다.
let과 const가 왜 생겼을까?
ES6 이전의 자바스크립트 프로그램에서는 var 예약어로만 변수를 선언할 수 있었다.
예약어 var를 사용한 변수는 함수 영역의 스코프를 가진다. 즉 스크립트 소스 전체에서 사용할 수 있는 변수이다.
그래서 실수로 var 예약어를 빠트리면 의도하지 않게 전역변수가 되기도 하고 프로그램 길이가 길어지다보면 실수로 사용하는 변수를 다시 재선언하거나 값을 재할당 해버리는 경우가 생기기도 했다.
var 예상하지 못한 프로그램 오류를 발생시키는 것은 물론, undefined라는 값이 포함되어있기 때문에 오류의 원인을 찾기도 어렵다는 단점이 있다.
이러한 이유 때문에, ES6버전부터는 var의 단점을 보완한 let과 const라는 예약어가 새롭게 등장했다.
let과 const도 var와 마찬가지로 변수를 만드는 키워드이다. 현재 var를 사용하지 않기를 권장하는 추세이다.
let
let은 변수를 만드는 새로운 키워드로 재할당은 가능하지만 재선언은 불가능한 변수를 만든다.
그렇기 때문에 var 변수처럼 호이스팅되거나 이름이 중복되어 코드의 에러를 발생시킬 일이 없다.
만약 중복하여 선언하였을 경우 위와 같이 개발자도구(F12)에 오류 코드가 발생한다.
let으로 선언하기 전에 변수만으로 먼저 실행했을 경우에도 오류 메세지를 나타낸다.
// 기본형
let 변수명;
let 변수명 = 값;
예시로 let을 사용해 보겠다.
clacSum() 이라는 함수를 선언하여 함수 내부에서 let으로 sum이라는 지역 변수를 선언하였다.
sum은 clacSum의 내부에서 선언되었기 때문에 그 내부에 있는 함수에서는 변수가 활용이 가능하지만,
바깥에서는 사용이 불가능하다.
하지만 지역 변수로 선언해 놓은 것이기 때문에 함수 바깥에서는 선언이 가능하다.
또한, let은 재선언은 가능하지만 재할당은 불가능한 예약어이다.
그렇기 때문에 sum = 100 이라는 식으로 재할당은 가능하지만 let sum으로 재선언은 불가능하다.
clacSum(); //함수는 미리 선언해도 호출이 가능하다.
function clacSum() {
let sum = 0; //함수 선언
for (let i = 1; i <= 100; i++) {
sum += i; //함수 사용
}
sum = 100; //재할당 가능
console.log(sum);
let sum=12; //재선언 불가능!
}
let sum = 0; //함수 바깥에서 선언하였으므로 선언가능
예시를 통한 내용 복습
아래 예시를 통해 let과 ver의 차이와 지역함수와 전역함수의 차이를 직접 비교해 보겠다.
추가로 함수 호출의 위치에 따라 결과값이 달라지는 이유와 오류가 발생할 경우 그 밑의 모든 코드들이 보이지 않는 현상도 확인해 보도록 하겠다.
// displayNum 함수
function displayNum() {
// 실행할 코드
console.log("a is :" + a);
console.log("b is :" + b);
console.log("c is :" + c);
console.log("d is :" + d);
// 지역함수
var b = 5;
let d = 7;
}
// 전역함수
var a = 1;
let c = 3;
// 함수호출
displayNum();
displayNum이라는 함수를 하나 만들어 지역변수와 전역변수일때 let과 var의 차이를 확인해 보겠다.
위의 예시로 필자는 3가지를 비교해 보겠다.
1. 실행할 코드와 변수의 위치
현재 실행할 코드는 console.log()이고 이며 변수들보다 앞에 위치해 있다.
선언된 변수 a, b, c, d 는 var과 let을 비교해 보기위해 지역변수와 전역변수로 각각 선언되었으며,
console.log로 제대로 실행되는지 확인해 보기 위해 각각의 값이 들어있다.
현재 실행할 코드 console.log는 변수들보다 앞쪽에 위치해 있다.
위에서부터 아래로 읽는 코드의 특성상 변수가 발생하는것이 맞지만 결과를 확인해 보면 아래와 같다.
function displayNum() {
console.log("a is :" + a);
console.log("b is :" + b);
console.log("c is :" + c);
console.log("d is :" + d);
var b = 5;
let d = 7;
}
var a = 1;
let c = 3;
displayNum();
전역함수 var로 선언한 a는 아래에 적었음에도 불구하고 들어있는 값인 1을 제대로 출력했다.
지역함수 var로 선언한 b는 오류는 뜨지 않았지만 undefined라는 값을 출력했다.
전역함수 let으로 선언한 c는 var과 마찬가지로 3을 제대로 출력한다.
마지막으로 지역함수 let으로 선언한 d는 d에 접근할 수 없다며 오류가 난 위치까지 정확하게 메세지가 뜨며 알려준다.
이런 형태로 오류의 원인을 찾을 수 있게 되기 때문에 전역함수보단 지역함수를, var 보단 let을 사용하는 것이다.
2. 함수 호출 위치
사실 함수는 위치에 상관없이 호출할 수 있다.
함수의 위쪽에서 부르거나 아래쪽에서 부르거나 상관없이 부를 수 있는것이다.
하지만 아래와 같이 지역함수와 전역함수가 섞여 있는 경우에는 다른 결과물을 보여준다.
// 함수 호출
displayNum();
function displayNum() {
console.log("a is :" + a);
console.log("b is :" + b);
console.log("c is :" + c);
console.log("d is :" + d);
var b = 5;
let d = 7;
}
var a = 1;
let c = 3;
// 함수 호출
displayNum();
2-1. 함수 호출을 아래에서 할 경우
함수호출을 아래에서 할 경우 지역함수 let으로 선언한 d를 제외하고 모두가 값을 반환한다.
2-2. 함수 호출을 위에서 할 경우
함수 호출을 위에서 할 경우 let으로 선언한 모든 변수들은 오류가 발생한다.
이유는 var로 선언한 변수들은 호이스팅되지만 let으로 선언한 변수들은 안되기 때문이다.
3. 오류 위치
자바스크립트는 오류가 발생하면 그 아래의 모든 함수들의 내용이 보이지 않는다.
function displayNum() {
// 오류가 발생하는 변수 d를 제일 먼저 호출했을 경우
console.log("d is :" + d);
console.log("a is :" + a);
console.log("b is :" + b);
console.log("c is :" + c);
var b = 5;
let d = 7;
}
var a = 1;
let c = 3;
displayNum();
오류가 발생하는 변수 d를 가장 앞으로 가져와 봤다.
아래와 같이 d에 접근할 수 없다는 오류창만 뜨며 이전에 값이 나왔던 것들도 모두 보이지 않는다.
Gemini / 오류코드 검사 ai ?
오류코드에 마우스를 올리면 우측에 전구 아이콘이 뜬다.
이를 클릭하면 개인정보 보호 공지가 뜨며, NEXT 를 눌러 수락하면 오류 코드를 보는데 도움을 주는 모양이다.
Learn more 을 클릭하면 Gemini가 무엇이며 어떻게 사용할 수 있는지에 대해 설명하는 링크가 나온다.
https://developer.chrome.com/docs/devtools/console/understand-messages?s=1&hl=ko
const
const 역시 let이나 var와 마찬가지로 변수를 만드는 키워드이다.
이름에서 알 수 있듯이 const로 선언한 변수는 '상수 변수'(constant variable)이다.
constant의 뜻은 어학사전에서도 알수 있듯이 변함없다는 뜻이다.끊임없는, 거듭되는 이라는 단어도 그 느낌이 변화가 있다는 느낌보다는 '변함없이 계속된다'는 의미 정도로 받아드리면 된다.
프로그램 안에서 상수는 ' 변하지 않는 값 '을 뜻한다. 즉, 변하면 안되는 값을 변수로 선언할 때 const를 사용하는 것이다.
프로그램에서 특정한 상숫값을 자주 사용한다면 변수에 담아서 사용하는 것이 편리하다.
const로 선언한 변수는 값을 재할당하거나, 이름을 재선언할 수 없다.
let을 사용한 변수처럼 블록레벨의 스코프를 가진다.
const 예시
currentYear는 이미 선언된 변수이기 때문에 다시 사용할 수 없다.
const는 재선언이 불가한 예약어이다.
const currentYear = 2024;
const currentYear;
currentYear는 상수변수이기 때문에 값을 재할당 할 수 없다.
const는 재할당이 불가능한 예약어이다.
const currentYear = 2024;
currentYear = 2022;
const는 상수변수이기 때문에 선언만 하는 것은 불가능하다.
반드시 값도 함께 넣어야한다.
const currentYear;
const로 선언된 값을 가져와 사용할 수 있다.
const currentYear = 2024;
let year = currentYear + 20;
console.log(year);
상수 변수 안에 배열이 들어있다면 배열 자체는 바꿀 수 없지만 배열 안에 있는 데이터는 바꿀 수 있다.
const array = [50, "hi", true, null];
// 배열에서 인덱스 번호 1번째 데이터를 꺼내서 let chocolat1에 할당하는 것은 가능하다.
let chocolat01 = array[1];
console.log(chocolat01);
// 상수 변수 array 배열 안에 있는 인덱스 1변의 데이터를 직접 바꾸는 것도 가능하다.
array[1] = "bye";
console.log(array[1]);
// 상수 변수 array 배열의 마지막 인덱스에 '마지막'이라는 데이터를 추가하는 것은 가능하다.
array.push("마지막");
console.log(array);
하지만 배열 자체를 바꾸는 것은 불가능하다.
array 안에는 원래 배열이 들어있었는데 배열 자체를 지우고 문자열을 넣으려고 하면 오류가 발생한다.
즉, 배열 안에 있는 데이터를 바꾸는 것은 가능하나 배열 자체를 다른 값으로 불가능하다.
const array = [50, "hi", true, null];
array = "안녕하세요";
자바스크립트에서 변수를 사용할때
자바스크립트는 유연해서 편리한 언어이다. 자유롭게 문장을 구성할 수 있다.
하지만 이런 편리성은 프로그램이 커지면 가독성이나 디버깅을 하기 어렵게 만든다.
자바스크립트 문법은 벗어나지 않으면서 가독성은 높히고 디버깅 하기 쉽게 하귀 위해서는
변수를 사용할 때 아래와 같이 사용하면 좋다.
1. 전역변수는 최소한으로 사용한다.
전역변수는 프로그램 어디에서는 접근할 수 있으므로 편리하게 사용할 수 있다.
하지만 예상하지 못한 곳에서 오류가 발생할 확률이 높다.
그래서 되도록이면 전역변수는 최소한으로 사용하는 것이 좋다.
2. var 변수는 함수의 시작부분에서 선언한다.
var를 이용한 변수는 어디에서 선언하든 상관없지만 내부에서 호이스팅이 생기므로 오류가 발생할 확률이 높다.
그래서 var 변수는 함수 시작 부분에서 선언하는 것이 변수를 확인하기에도 좋고 오류를 줄일 수 있다.
3. for문에서 카운터 변수를 선언할 때 var 예약어를 사용하지 않는다.
for문 안에서만 사용할 카운터 변수는 그 블록 안에서만 사용할 것이므로 가끔 var를 이용해서 선언하기도 한다.
하지만 이렇게 선언한다고 해서 블록 변수가 되는 것은 아니기 때문에 for문에서 사용할 때에는
let을 이용하거나 for문 바깥에서 선언하는것이 좋다.
// 블록 바깥에서 var로 선언할 경우
function(){
var i;
{for(i = 0; i < 10; i++){
자바스크립트코드;
}
}
// let을 이용해서 블록 변수로 선언
function(){
{for(let i = 0; i < 10; i++){
자바스크립트코드;
}
}
4. ES6를 사용한다면 예약어 var 보다는 let을 사용하는 것이 좋다.
var 를 사용한 변수는 재선언할 수 있기 때문에 실수로 같은 변수 이름을 다시 선언하더라도 오류가 발생하지 않는다.
간혹 여러 사람이 한 프로그램을 같이 작업하다 보면 변수 이름이 중복되면서 서로의 코드를 망가트릴 수 있다.
let 을 사용하여 이름의 중복을 막아 코드 오류를 줄이는 것이 좋다.
'자바스크립트(JavaScript) > 자바스크립트' 카테고리의 다른 글
[JavaScript] 함수의 값을 반환하는 return 문 (0) | 2024.07.29 |
---|---|
[JavaScript] HTML 태그 불러오는 방법 (0) | 2024.07.26 |
[JavaScript] 함수란? (0) | 2024.07.26 |
[JavaScript] 일정한 시간 간격으로 코드 실행하고 중지시키기 / setInterval(), setTimeout() (0) | 2024.07.24 |
[JavaScript] 브라우저 객체 모델(Browser Object Model) (0) | 2024.07.23 |