티스토리 뷰

안녕하세요. 좋아요요정입니다

 

다들 이야기합니다. var를 쓰지마세요 등짝스매싱! 

그래서 준비했습니다 var 외 않대요? 

var, let 키워드로 변수를 선언한 상태를 살펴보고, var를 쓰면 안 되는 이유를 이해해보는 시간을 가지겠습니다.

 

 

 


var 👻

ES5 이전까지는 var를 사용하여 변수를 선언했다고 합니다.

var에게는 자바스크립트를 더욱 다이나믹하게 만들어주는 엄청난 능력이 있었습니다.

 

1. 변수의 중복 선언 허용

var x = "오렌지꿀주먹";
var x = "오렌지똥주먹";
console.log(x) //"오렌지똥주먹"

var 키워드로 선언한 변수는 중복으로 선언이 가능합니다. 사용했던 변수명인 것을 까먹고 다시 선언한다면? 그렇게 시간은 흐르고 흘러 유지보수를 할 때 이전에 사용했던 변수명을 발견하게되는데...!!!  생각만해도 아찔하죠? 

 

var y = "허니빔";
var y;
console.log(y)//"허니빔"

중복으로 선언하며 값을 할당하지 않게되면 심지어 이전 값이 할당됩니다.

이런 엄청난 능력으로 인해 개발자의 실수로 변수를 중복 선언하게 되면, 원치않는 사이드 이펙트가 발생할 수 있습니다.

 

 

2.  함수 레벨 스코프

var x = "오렌지꿀주먹";

function sayHi() { //함수 레벨 스코프
	var x = "hello";
	console.log(x)
}
sayHi()

console.log(x)//"오렌지꿀주먹";

if(true) { //블록 레벨 스코프
	var x = "💩";
}

console.log(x) //"💩"

var  키워드로 선언한 변수는 오로지 함수 코드 블록만을 지역 스코프로 인정합니다.

함수 레벨 스코프 sayHi()에서 선언된 x의 값은 함수에서만 사용되어지고 전역 변수 오렌지꿀주먹이 바뀌지 않았지만,

블록 레벨 스코프 if문 안에서 선언된 x의 값은 중복 선언으로 인정되어 전역 변수 오렌지꿀주먹의 값이 으로 변경되었습니다.

 

 

3. 변수 호이스팅 발생

var로 선언하면 호이스팅으로 인해 선언문들이 스코프의 선두로 끌어올려진듯 동작합니다. 따라서 코드블럭에서 선언을 하기 이전에도 참조하고, 심지어 값을 할당할 수 있습니다. 

console.log(x)
x = "허니파워";
console.log(x)
var x;

처음에 출력한 console.log(x)에서는 초기화되어있는 undefined, 

값을 할당한 뒤 출력한  console.log(x)에서는 허니파워가 출력되는 것을 볼 수 있습니다.

 

var가 호이스팅이 되지 않고, 애초에 x를 사용할 수 있는 것이 아닌가에 대한 의문을 해소하기 위해

선언문 없이 입력하면 x가 선언되지 않았다는 에러메세지를 확인하실 수 있습니다.

 

 

 

만약 전역변수를 선언하지 않고 블록 레벨 스코프 안에 선언하면 어떻게 될까요?

console.log(x)//undefined;
if(true) {
	var x = "날파리";
}

코드 블록에서 선언한 변수가 글로벌 영역으로 호이스팅되어 전역변수로 선언되고 undefined으로 초기화되어있는 것을 볼 수 있습니다.

이처럼 var는 코드 블록 내에서 선언해도 함수 레벨 스코프가 아닌 경우 모두 전역 변수가 됩니다. 전역 변수의 선언이 많아지면 쉽게 사이드이펙트가 발생할 수 있습니다.

 

 

 

4. 전역변수로 선언 시 전역 객체의 프로퍼티로 등록

글로벌 스코프에서 var로 선언한 변수와 키워드 없이 값이 할당된 변수, 함수의 경우 브라우저의 전역 객체인 window의 프로퍼티로 등록됩니다. 

 

 

전역변수의 문제점

젼역 변수의 경우 프로그램이 실행될 때 선언되며 프로그램이 종료될 때까지 메모리 공간을 점유하게 됩니다. 
어디서든 참조할 수 있다는 장점이 있지만, 위와 같은 블록 레벨 스코프 안에서 중복 선언되거나 다른 함수에서 값을 재할당하게될 수 있습니다. 그리고  블록 레벨 스코프 안에서 선언된 변수의 값까지 모두 전역 변수가 될 경우 메모리를 점유하는 공간은 늘어나고 원치 않는 사이드이펙트가 발생할 수 있습니다.

 

 


 

var의 능력은 대단한 능력이지만, 이로 인해 발생되는 문제점들을 보완하기 위해 ES6에서는 변수를 선언하는 키워드가 새로 도입되었습니다. 바로 let과 const입니다.

 

 

 

let😺

1. 변수 중복 선언시 문법에러 발생

let x = "오렌지꿀주먹";
let x = "오렌지똥주먹";

이미 선언되어있는 변수를 중복 선언할 경우 식별자 x가 이미 선언되었다는 문법에러가 발생합니다.

 

 

2. 블록레벨 스코프 인정

let x = "오렌지꿀주먹";

function sayHi() { //함수 레벨 스코프
	let x = "hello";
	console.log(x) //"hello"
}
sayHi()

console.log(x)//"오렌지꿀주먹";

if(true) { //블록 레벨 스코프
	let x = "💩";
}

console.log(x) //"오렌지꿀주먹"

함수 레벨 스코프만 인정한 var와는 다르게  let은 블록 레벨 스코프도 지역 스코프로 인정합니다.

가장 마지막에 출력한 x의 값이 함수와 블록레벨의 선언값들에 재할당되지 않고 처음에 선언된 "오렌지꿀주먹"값을 그대로 가지고 있습니다. let은 코드블럭 내부에서 선언되는 값은 스코프 안에서만 존재하여 글로벌에 선언된 값과는 별개의 변수로 존재합니다. 

 

 

if(true) { //블록 레벨 스코프
	let x = "💩";
}
console.log(x)

블록 레벨 스코프 안에서 선언된 let 값은 외부에서 참조할 수 없습니다.

 

 

 

3. 변수 선언 전 참조시 에러 발생

var 같은 경우 블록 레벨 스코프에서 선언되어도 호이스팅이 발생했고, 선언하기 이전에 참조하고 값을 할당할 수가 있었습니다. 

똑같은 코드를  let 키워드로 선언하면 어떻게 될까요?

console.log(x);
x = "허니파워";
console.log(x);
let x;

console.log(x)
if(true) {
    let x = "날파리";
}

선언 전에 참조하거나, 값을 할당할 때와 블록 레벨 스코프에서 선언하기 전에 참조할 때 모두 ReferenceError가 출력됩니다. 

 

 

let은 호이스팅이 발생하지 않은 것일까요?

let 키워드로 선언한 변수는 호이스팅이 발생하지 않는 것처럼 동작합니다.

let키워드로 선언한 변수는 변수 선언 단계와 초기화 단계가 분리되어 진행됩니다. 

 

 

 

var 키워드로 선언하는 경우

1. 프로그램이 실행됩니다.

2. 자바스크립트 엔진이 런타임 이전에 코드를 해석합니다.

3. 이때 var키워드로 선언된 변수에는 변수의 선언과 동시에 값 초기화가 한번에 진행됩니다.

따라서 코드를 실행하기 이전인 선언 단계에서 이미 스코프에 변수 식별자를 등록하게 되고, undefined값으로 초기화되어집니다.

4. 코드가 진행됩니다. 

5. 변수에 값이 할당되는 위치에서 값이 할당되어집니다. 

 

 

let 키워드로 선언하는 경우

1. 프로그램이 실행됩니다.

2. 자바스크립트 엔진이 코드를 해석합니다.

3. 이때 let 키워드로 선언된 변수는 선언이 되어지고, 코드 내에서 실제로 선언이 되어질 때까지 참조를 막습니다.

   이 구간을 일시적 사각지대라고 부릅니다. 

4. 코드가 진행이 되어집니다.

5. 변수가 선언되는 위치에서 초기화가 진행됩니다.

6. 변수에 값이 할당되는 위치에서 값을 할당하게 됩니다.

 

 


 

 

변수가 호이스팅이 되었다는 것을 어떻게 알 수 있을까요? 

변수가 실제로 선언되어지지 않았을 때와 let 키워드를 선언하기 이전과 동일한 에러가 출력이 됩니다.

let 키워드를 선언하기 이전에 참조할 때
변수가 실제로 선언되어지지 않았을 때

 

 

하나의 코드를 더 확인해보겠습니다.

let x = "오렌지꿀주먹";
if(true) {
	console.log(x)
    let x = "1";
}

전역변수 x가 선언되어 있고, 블록 레벨스코프에서 x를 출력한 후 블록 레벨 스코프에서 사용될 x를 선언하는 코드입니다. 

 

콘솔에는 초기화 하기 전에 x를 엑세스할 수 없다는 에러가 출력됩니다.

이는 블록 레벨 스코프의 코드가 실행이 될 때, 코드를 해석하고 해당 코드 내의 변수를 미리 선언한 뒤 참조를 막았기 때문입니다.

코드블럭 내에서 실제로 선언되기 이전에 전역 변수를 참조하지 못한 이유는 블록 레벨 스코프의 메모리 영역에서 x를 찾았기 때문에 에러가 출력되는 것이기 때문입니다. 

 

 

 

4. 전역 변수에 선언해도 전역 객체에 등록되지 않음

let으로 선언한 변수의 경우 전역 객체의 프로퍼티로 등록되지 않고 글로벌 스코프 내의 변수로 선언됩니다. 

 

 


 

저는 var를 마치 볼트모트처럼 무의식 중에 사용을 피하고 있었습니다.

var를 쓸 때 따라오는 '안돼!!'소리...💩ㅎㅎ

블로그들과 교재에서 사용되어지는 var를 보면서도 불안한 마음이 들었는데, 이렇게 차이점들에 대해 자세하게 알아보니 키워드가 가지고 있는 특징이 다르다는 것을 알게 되었고, 실제 프로젝트를 진행할 때 사용을 자제하여도, 블로그 글 작성이나 간단한 예시에서는 '절대 안돼!'는 키워드는 아니라는 것을 알게 되었습니다.  그쵸.. 절대 안되는 경우라면 ES6가 되자마자 사라졌겠죠..? 

var, let, const와 블록 레벨 스코프에 대해 전부를 다루고자 했는데, 예시가 길어지고 호기심에 몇개의 시도를 더 진행해보니 게시글이 많이 길어졌습니다. let과 const의 차이점에 대해서 이어서 작성하도록 하겠습니다. :) 

 

새해 이후 첫 주말이네요. 

새해에 세운 목표를 되새기며, 남은 1월도 파이팅하길 바랍니다! 감사합니다. 

 

JavaScript 스터디 팀 러버덕과 함께 합니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/06   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
글 보관함