const || let || var

Taeseon Kim·2021년 8월 10일
0
post-thumbnail

변수 선언에서 필요한 문법이다.

ES2015+ 이전 버전의 js만 해도 변수를 선언하는 방법은 var를 사용하는 방법이 통용되었다.

아래에서도 많이 언급할테지만 재선언이 가능하고, 호이스팅이 실행되며, 상수 활용이 불가능하다는 점이 코드를 작성함에 있어 어려움을 줄 수 있는 방법이다.

먼저 ES2015+ 이전 버전에서 통용되던 var의 특징에 대해 간략하게 설명해보겠다.

1. 재선언이 가능하다.

var byeonSu = 1;
var byeonSu = 2;

현재 내게 익숙한 const나 let에서는 말도 안되는 선언 방법이다.
물론 이 방법이
어떻게 실드를 쳐보려 노력해도 불가능한 것 같다. 이는 너무 비효율적이고 점점 길어지는 코드에서는 보수가 어려운 방식이다.
또한 이러한 재선언이 가능하다는 var의 특성은 또 다른 문제를 낳는다.

2. 함수 레벨 스코프를 가진다.

var byeonSu = 'global';// 1
function ex() {
  var byeonSu = 'local';// 2
  byeonSu = 'change';
}
ex(); 
console.log(byeonSu);

이 짧은 코드에서 마지막 console.log(x)는 1번 변수와 2번 변수 중 무슨 값을 출력해낼까?

정답은 global이다.

수도코드와 함께 보자.

var byeonSu = 'global'; //1 //전역 스코프를 가지는 byeonSu 변수 선언
function ex() {
  var byeonSu = 'local'; //2 // ex함수 내의 스코프를 가지는 byeonSu 변수 재선언
  byeonSu = 'change'; // 해당 줄로부터 가장 최근에 선언한 byeonSu를 찾아 재할당
}
ex(); //따라서 ex함수가 실행될 때, ex함수 내의 변수의 값이 
//'local'에서 'change'로 바뀐다.
console.log(byeonSu); // 하지만 전역에서 불러낸 byeonSu변수는 전역 스코프를 가진
//1번째 줄의 byeonSu변수이기에, 출력 값은 'global'이다.

1번 변수와 2번 변수처럼 같은 변수명으로 재선언된다면, 해당 변수명을 가진 전역 변수(1번 변수)와 함수 스코프 내의 변수(2번 변수)는 다른 변수로 인식하는 것으로 보인다.

따라서 변수명을 제대로 관리하지 않는다면 원치 않은 결과값을 얻을 수 있다는 단점으로 다가온다.

함수 레벨 스코프는 또 다른 문제가 있는데, 아래 코드를 보자.

for(var i = 0; i < 3; i++){
  console.log(i);
};
console.log('global' + i);

이 코드는 반복문을 통해 0,1,2의 값을 차례대로 출력하는 것을 목표로 한다.
하지만 var로 선언된 i는 함수 레벨 스코프이기에, 현재 var i = 0이 선언된 곳은 반복문 조건식 안이다.
반복문 조건식은 함수에 해당하지 않기 때문에 해당 var i = 0 식은 전역 변수 처리가 되어 실제 출력되는 값은 0,1,2,'global3' 이 될 것이다.

3. 호이스팅

console.log(byeonSu);
var byeonSu = 'bye';

호이스팅은 자바스크립트 내에서 함수 실행 전, 함수에 필요한 변수들을 모두 코드 실행 최상위 순서로 올려버리는 것을 의미한다.

var는 실행시 호이스팅을 통해 제일 최상위 순서로 배치되는데, 따라서 위 코드에서는 byeonSu변수가 호이스팅을 통해 console.log 실행문 보다 먼저 실행된다. console.log에 전달된 인자인 byeonSu에는 console.log 실행문 기준 가장 최근에 실행된 byeonSu 변수가 전달되게 된다.

var의 문제점을 해결하기 위한 새로운 방법의 등장!

이러한 var의 문제점과 더불어, 상수의 필요성이 제기되어 ES2015+버전 부터는 새로운 변수 선언 방법으로 const, let이 생기게 되었다.

const와 let의 공통점은 위 var의 단점을 반대로 한 것과 같다.

const와 let의 공통점
1. 재선언이 불가능하다.
2. 블록 레벨 스코프를 가진다. (반복문, 조건문 등의 조건식에서 선언된 변수라도 전역에서 사용이 불가능하다.)
3. 호이스팅이 불가능하다. (선언 - 초기화 - 할당의 과정이 따로 이루어진다.)

또한 이 둘의 차이점 또한 정말 간단한데, 간단한 예시로 소개하고 마무리해보겠다.

const a = '1';
let b = '2';
function newNum () {
	a = '3';
  	b = '4';
}
newNum();
console.log(a);
console.log(b);

이 코드의 경우 어떤 출력 값이 나오게 될까.

사실 정답은 '이 코드는 실행할 수 없다.' 이다.

let은 어찌보면 var와 비슷한 변수 선언 방식인데, 다른 점은 재선언이 불가능하다는 점이다.

만약,

const a = '1';
let b = '2';
function newNum () {
	a = '3';
  	let b = '4'; // 요기가 바뀐 것 같은데,,?
}
newNum();
console.log(a);
console.log(b);

함수 안에서 let b 를 통해 다시 한번 변수를 선언했다면, 코드는 진행되지 못할 것이다.(저게 아니더라도 진행을 못하지만)

다시 원래 코드로 돌아가서, let은 재'선언'은 불가능 하지만 재'할당'은 가능하다. 결국 동적으로 데이터 값을 저장하고 싶다면 let을 사용하면 var보다 편하게 사용이 가능하다는 말이다.

const는 상수를 저장하는 방법이다. 위의 코드가 작동되지 않았던 이유는 바로 const가 선언된 변수에 재할당을 시도했기 때문이다.
따라서 위의 코드가 실행되기를 원한다면, const로 선언된 변수를 let 선언으로 바꾸거나, 다시 선언되는 코드를 제거하면 실행될 것이다. 적어도 결과가 어떻게 나오는지는 자랑하고 싶기에, 다른 방식으로 const의 값을 바꿀 수 있는 식을 만들어보겠다.

const a = [1];// 요기가 바뀌었습니다
let b = '2';
function newNum () 
	a.push(2);// 요기두요
  	b = '4';
}
newNum();
console.log(a);
console.log(b);

이 경우 [1, 2], 4의 출력값을 얻을 수 있을 것이다.
console.log(b)의 값은 let로 선언한 변수이기에 재할당이 가능하므로 4가 출력될 것인데,
console.log(a)의 값은 const로 선언한 변수인데 어떻게 값이 변할 수 있었을까?

왜냐하면 배열은 참조 자료형이기 때문에 참조 주소자체가 바뀌지 않는 한, const로 선언한 a의 값을 변경하는 것도 가능하다.

profile
공부하여 이해가 된 것만 정리합니다.

0개의 댓글