ES5까지 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었다.
var는 주의를 기울이지 않으면 여러 문제를 야기하게 된다.
var 키워드는 초반의 블로그 내용에서 다루었기 때문에 앞부분의 포스팅을 참고해보자.
다시 한 번 문제점에 대해서 이야기해보자면 .
1.변수의 중복 선언 허용
2.함수 레벨 스코프
3.변수 호이스팅 문제
이런 대표적인 문제가 있었다.
var의 잠재적 문제점때문에 ES6에선 let과 const가 등장했다.
let 과 const는 변수의 중복 선언이 금지된다.
또한 var는 함수 레벨 스코프를 가지지만 let과 const는 블록레벨 스코프를 가진다.
블록레벨 스코프를 이해하기 전에 먼저 지역 변수와 전역 변수가 존재하는데 ,
전역변수는 {}에 감싸져있지 않은 외부의 변수를 말한다.
반대로 지역변수는 {}라는 지역에 살고있는 변수라고 생각하면 편하다.
코드로 예를 들어보자.
<script>
let foo = 1; 전역 변수 //
{
let foo = 2; //지역변수
let bar = 3;//지역변수
}
console.log(foo) //1
console.log(bar) //ReferenceError: bar is not not defined
</script>
이번엔 전역 스코프 , 함수 레벨 스코프 ,블록 레벨 스코프에 대해 알아보자.
<script>
let i = 10; // 전역 스코프
function foo() {
let i = 100; // 함수 레벨 스코프
for (let i = 0; i < 3; i++) {
console.log(i); // 1 2 블록 레벨 스코프
}
console.log(i); //100
}
foo();
console.log(i); //10
</script>
스코프{} << 이녀석 안에 있는 변수 녀석들은 코드의 실행이 끝나면 생명주기를 잃는다.
하지만 우리가 나중에 배울 클로저와 실행컨텍스트에선 클로저의 효과로 {}안에 선언된
변수가 좀비처럼 살아있을 수 있다 . 그 부분에 대해선 포스팅을 이어나가면서 설명하겠다.
자바스크립트는 let ,const를 포함한 모든 선언(var,let,const,function,class)을 호이스팅한다.
단 var 키워드로 선언한 변수와 달리 let , const ,class 는 변수 호이스팅이 발생하지 않는것처럼 동작한다.
var키워드로 선언한 변수는 런타임 이전에 선언 단계와 초기화 단계가 실행된다.
선언단계 초기화단계가 동시에 이루어지고 그 다음 단계에서 할당 단계가 실행된다.
하지만 let으로 선언한 변수는 선언단계와 초기화단계가 분리되어 진행된다.
즉 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행된다.
하지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
만약 초기화 단계가 실행되기 이전에 변수에 접근하려하면 참조에러가 발생한다.
스코프의 시작 지점부터 초기화 시작 시점까지 변수를 참조할 수 없는 구간을
일시적 사각지대 (TDZ : temporal Dead Zone 이라고 부른다.)
코드로 예를 들어보자.
<script>
//런타임 이전에 선언 단계 실행 . 아직 변수 초기화 되지않음
//초기화 이전에 변수를 참조할 수 없다.
console.log(foo); //ReferenceError:foo is not defiend
let foo; //변수 선언문에서 초기화 단계가 실행된다.
console.log(foo); //undifined
foo = 1; //할당문에서 할당 단계가 실행된다.
console.log(foo); // 1;
</script>
const는 또한 선언과 초기화를 반드시 동시에 초기화해야한다.
const foo = 1;
const fool SyntaxError:Missing initializer in const declaration
const 키워드로 선언한 변수는 let키워드로 선언한 변수와 같이 블록스코프를 가진다.
변수 호이스팅또한 발생하지 않는 것처럼 동작한다.**
const 의 특징은 재할당 금지이다.
하지만 const 키워드로 선언된 변수에 객체를 할당하는 경우 값을 변경할 수 있다.
코드로 예를 들어보자
<script>
const person = {
name: "Lee",
};
person.name = "kim";
console.log(person); //{name:"kim"}
</script>
const 키워드는 재할당을 금지할 뿐 "불변"을 의미하지는 않는다.
새로운 값을 재할당하는 것은 불가능하지만 프로퍼티 동적 생성 , 삭제 ,값의 변경을 통해
객체를 변경하는 것은 가능하다.
객체가 변경되더라도 변수에 할당된 참조 값은 변경되지 않는다 .
오늘은 꽤나 복잡한 내용의 스코프를 다루었다 .
이 개념이 잘 잡혀야 클로저 ,실행컨텍스트를 잘 이해할 수 있기에 꼼꼼하게 공부하자.