var, let, const 선언자

웅로그·2022년 11월 15일
0

1. 개요

선언자는 자바스크립트에서 가장 기본적인 내용이다. 기본적이지만 핵심적인 내용으로 선언자에 대해 깊이 있는 내용을 알면 자바스크립트의 작동 방식에 대한 이해가 높아진다. 따라서 깊이 있게 공부할 필요성이 있다. 이 글에서는 선언자를 제대로 이해하기 위한 scope에 대한 내용과 var, let, const 각 선언자별로 작동방식과 특징에 대해 알아볼 것이다. 더 나아가 자바스크립트의 메모리 관리 방식에 대해서도 알아본다.


2. scope

선언자의 기능을 제대로 이해하기 위해 우선 scope 개념에 대한 이해가 필요하다. scope는 변수에 접근할 수 있는 범위를 말한다. 자바스크립트에서 scope은 범위에 따라 크게 function scope과 block scope으로 나뉜다. var, let, const 각각 선언 후 변수가 가지는 scope가 다른데 이것은 밑에 선언자 설명에서 다룬다.

2-1. function scope

함수 범위 내에서 선언된 변수는 그 함수 안에서만 접근 가능한 범위를 가진다. 이 범위를 function scope이라고 부른다.

아래 코드에서 num은 함수 안에서 선언됐고 function scope를 가진다. 따라서 num을 출력하면 오류가 나타난다.

코드

function name() {
    var num = 35;
}

console.log(num);

결과

2-2 block scope

block scope는 말 그대로 블록 안에서 선언된 변수는 블록 영역을 접근 가능한 범위로 가진다.

아래 코드에서 num은 if문 안에서 선언됐고 block scope를 가진다. 따라서 if문 안에서만 사용할 수 있는 것이다.

코드

if (1) {
    let num = 1;
}

console.log(num);

결과


3. var 선언자

같은 변수명을 여러번 선언할 수 있는 선언자이다. 즉 재선언이 가능하다. 또한 function scope를 따른다. 재선언이 가능하다는 문제 때문에 기존에 선언된 변수를 프로그래머가 자기도 모르게 재선언하여 덮어씌울 수 있는 위험성이 있다. 이 외에도 호이스팅 및 function scope 특성 때문에 문제점이 있는 선언자이다. 따라서 ES6이후로는 var선언자는 잘 쓰이지 않는다. 바로 아래에서 var 선언자의 문제점을 다룬다.

3-1. var 선언자의 사용법

다음과 같은 형태로 사용한다.

var 변수명 =;

값을 할당하지 않은 상태로도 선언 가능하다.

3-2. var 선언자의 문제점

3-2-1. 같은 변수를 계속 선언할 수 있음

var name = 'bathingape'
console.log(name) // bathingape

var name = 'javascript'
console.log(name) // javascript

같은 변수를 두번 선언했음에도 오류가 나지 않고 출력되는걸 볼 수 있다. 이는 코드량이 많아지게 되면 변수가 어디에서 어떻게 사용되었는지 파악하기 힘들고 선언된 값을 의도치 않게 바뀌게 하여 혼란을 초래한다.

3-2-2. function scope에 따른 문제

for (var i = 0; i < 5; i++) {
  console.log(i);
}

console.log('last:', i);

// 0
// 1
// 2
// 3
// 4
// last: 5

위와 같이 for문이 끝난 이후에도 for문 안에 선언했던 i변수 값을 읽을 수 있다. if문 안에서 선언한 변수를 if문 밖에서도 읽을 수 있다. 어떤 function에서 사용되었냐를 기준으로 scope이 정해지기 때문이다. 이런 점 때문에 var를 사용하면 코드를 분석하는데 어려움이 생기게 된다.

3-2-3 호이스팅에 따른 문제

호이스팅은 변수나 함수를 선언했을 때 그 선언된 함수나 변수가 코드의 최상단에 있는 것처럼 작동하는 것이다. 실제 선언된 코드보다 위의 코드에서 해당 변수나 함수를 호출해도 최상단에서 선언한 것처럼 작동해 문제없이 작동한다. 아래 코드를 보자.

function variable() {
  console.log(`n : ${n}`); // n : undefiend
  var n = 2;
  console.log(`n : ${n}`); // n : 2
}
variable();

var n = 1;

첫번째 출력문을 보면 n이라는 변수가 선언되기 전인데도 해당 변수가 출력이 되고 undefined라는 결과가 나온걸 볼 수 있다. 이것은 아래에서 선언한 n변수가 호이스팅되어 최상단에서 일단 var n;이라고 선언된 것으로 보기 때문이다. 호이스팅 될 때에는 변수에 값은 할당되지 않은 상태로 호이스팅이 일어난다. 따라서 처음에는 undefined라고 출력되고 var n = 2;라고 진짜로 선언된 다음에는 n에 2라는 값이 할당되어 2가 출력된다.


4. let 선언자

let은 ES6부터 지원하는 자료형이다. var선언자의 위와 같은 문제점들 때문에 나온 선언자이다. 선언된 블록 안에서만 쓰일 수 있는 블록 스코프를 가지게 된다.

4-1. let 선언자의 사용법

다음과 같은 형태로 사용한다. 값을 할당하지 않은 상태로 선언할 수 있다.

let 변수명 =;

4-2. let 선언자의 특성

4-2-1. block scope

let num = 10;

if (num == 10) {
    let num = 20;
    console.log("num in if : ", num); // num in if : 20
}

console.log(num); // 10

블록 영역이 다르면 같은 변수명으로 재선언할 수 있다. 하지만 위처럼 if문 안에서 선언된 let은 그 블록 안에서만 적용되고 if문 밖에서 접근할 수 없는 것을 볼 수 있다. for문 안에서 let으로 선언된 변수도 for문 밖에서는 사용할 수 없다.

4-2-2. 같은 블록 안에선 재선언 안됨

let name = 'bathingape'
console.log(name) // bathingape

let name = 'javascript'
console.log(name) // SyntaxError: Identifier 'name' has already been declared

name 변수를 같은 블록 안에서 재선언하여 오류가 발생했다.

4-2-3. 초기화 되기 전에 접근 금지

var와 똑같이 호이스팅은 되나 초기화 하기 전 변수에 접근하려 하면 ReferenceError를 발생시킴.

function variable() {
  console.log(`n : ${n}`);
  let n = 2;
}
variable(); //ReferenceError: n is not defined

변수n이 선언되기 전에 console.log로 호출하여 에러가 났다.


5. const 선언자

상수 선언자로 한번 선언하여 변수에 값을 지정하면 변수의 값을 바꿀 수 없다. 앞으로 값이 변할 경우가 없는 변수나 변수의 값을 고정하여 바뀔 수 없도록 하고 싶을 때 사용한다.

5-1. const로 선언자 사용법

다음과 같은 형태로 사용하며 값을 할당하지 않고 사용할 수 없다.

const 변수명 =;

5-2. const 선언자 특징

5-2-1. 값을 할당하지 않으면 오류가 발생한다.

const n; //SyntaxError: Missing initializer in const declaration

5-2-2. 값을 변경할 수 없다.

const n = 2;
n = 3; //TypeError: Assignment to constant variable.

위 특징 외에 다른 특징들은 let선언자와 똑같다. block scope을 가지고 같은 블록 안에선 재선언 할 수 없으며 초기화 되기 전에 접근이 금지된다.

5-3. const로 선언된 배열은 변경할 수 없을까?

변경 가능하다. 배열은 객체이고 const로 선언한 객체는 메모리값(객체가 저장된 공간)만 상수이고 객체안의 내용은 변경이 가능하다. 따라서 const로 선언된 변수는 재선언이나 재할당은 할 수 없지만 push(), pop()을 이용해 배열의 값을 추가하거나 삭제할 수 있다. 이와 관련한 자세한 내용은 자바스크립트가 메모리에 어떻게 저장되는지 알아야 한다. 아래 5-3-1에서 간단히 짚고 넘어가자.

다음과 같은 재할당은 할 수 없다.

// 오류
const arr2 = [];
arr2 = ['하이'];

다음과 같은 값을 추가하는 행위는 가능하다.

// 가능
const arr1 = [];
arr1.push('하이');

5-3-1. 스택과 힙 메모리 구조

자바스크립트에서는 정적 메모리 저장 공간인 스택(Stack) 영역과 동적 메모리 저장 공간인 힙(Heap)영역이 있다. 일반적인 변수 선언은 데이터 크기가 유한하고 정적이기 때문에 스택 영역에 저장되고 배열과 오브젝트 같은 객체는 데이터 크기가 동적으로 변경이 가능하기 때문에 힙 영역에 저장된다. 일반적인 변수같이 스택 영역에 데이터가 저장되는 것들은 값이 특정 메모리 주소의 스택 영역에 그대로 저장되지만 힙 역에 값이 저장되는 객체들은 스택 영역에는 값이 저장된 힙 영역의 메모리 주소가 저장되어 있다.

그림에서처럼 객체들은 스택 영역에 힙 영역의 메모리 주소가 저장되므로 const로 객체 선언을 하게 되면 스택 영역에 저장된 메모리 주소값이 고정되는 것이지 힙 영역에 저장된 값 자체는 고정되지 않는다. 따라서 const로 배열을 선언해도 배열 안의 값을 변경하거나 push(), pop()으로 값을 추가하거나 삭제하여도 문제가 되지 않는다. 하지만 재선언이나 재할당을 할 수는 없다. 재선언과 재할당은 해당 변수에 새로운 메모리 주소를 부여하는데 메모리 주소는 const로 선언하여 변수에 메모리 주소값이 고정되었기 때문이다.


6. 마치며

자바스크립트 선언자는 기본적이며 중요하다. 선언자 공부를 통해서 선언자의 기본적인 기능 뿐만 아니라 자바스크립트 자체에 대한 이해도를 높이는게 좋을 것 같다. 이번 글에서 기능과 동작 방식에 대해 기본적으로 다뤄야 할 내용은 다 정리해놨다고 생각한다. 좋은 참고글이 되기를 바란다.

profile
프론트엔드 개발자입니다.

0개의 댓글