변수와 스코프

2020. 2. 28. 17:27TypeScript&JavaScript/JavaScript

자바스크립트에서 변수를 선언하는 방식은 크게 var, let, const로 나뉜다. 현재는 ES6 이후의 문법이 크게 대중화 되어있고, var 보다는 let과 const를 사용하길 권장한다. 그 이유는 변수 스코프의 차이 및 선언, 호이스팅과 관련되어 있다.

작고 간단한 어플리케이션의 코드에서 var는 편리하다. 그러나 조금만 코드가 길어지고 어플리케이션이 복잡해지면, 암묵적 생략이나 함수 레벨 스코프를 이용하는 것은 오히려 독이 된다.

let과 const는 기본적으로 블록 레벨 스코프로 다뤄진다. 해당 변수가 선언된 코드블록 내에서만 유효하며 외부에서는 참조할 수 없고, 블록 내에서 지역변수로 다뤄진다.

호이스팅의 경우, 인터프리터 언어인 자바스크립트에서 선언문이 호출보다 뒤에 나오더라도 스코프의 선두로 옮긴 것처럼 동작하는 것을 뜻한다. var는 이러한 호이스팅의 특성이 있으나, let의 경우에는 참조에러가 발생한다.

변수의 생성은 선언 단계, 초기화 단계, 할당 단계로 나뉘어지는데, 

선언단계는 변수를 실행 컨텍스트의 변수 객체에 등록하고, 스코프가 참조하는 대상으로 만든다.

초기화단계는 변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다. 이 단계에서 undefined로 초기화 된다.

할당단계는 undefined로 초기화된 변수의 메모리 주소를 할당하고 값을 적용한다.

var 로 선언하는 변수의 경우, 선언과 초기화가 동시에 이뤄지지만, let 으로 선언하는 변수의 경우 선언과 초기화가 분리되어 진행된다. 따라서 스코프의 선두에서 변수를 선언하지만, 변수 선언문에서 비로소 초기화가 된다. 그렇기 때문에  메모리 주소에 대한 참조 에러가 나는 것이다.

전역객체의 경우 window객체 또는 global 객체를 의미하는데, var의 경우 window 객체의 활용이 가능하지만 let은 전역변수로 활용하더라도 블록스코프 특성상 개념적인 블록을 상정하기 때문에 window객체로 활용할 수 없다.

const는 일반적으로 상수를 선언하기 위해 사용한다. 하지만 반드시 상수만을 위해 사용하지는 않는다. 

기본적으로 const는 let과 비슷하나 중요한 차이가 있다.

const는 재할당이 금지된다. const는 선언과 동시에 할당이 이뤄져야만 한다. 이러한 특징은 객체를 선언할때도 드러나는데, const 변수의 타입이 객체인 경우, 객체에 대한 참조를 변경하지 못한다는 것이다. 그러나 이 때 객체의 프로퍼티가 보호받는 것은 아니라서, '재할당'이 불가능 한 것과 객체 프로퍼티의 내용을 변경하는 것의 차이를 인지하는 것이 중요하다. 프로퍼티의 추가, 삭제, 값은 변경가능한 것이다. 이것은 객체의 내용이 변경되더라도, 객체 타입 변수에 할당된 메모리 주소값은 변경되지 않기 때문이다. 

let과 const를 사용하기를 권장하는 ES6 이후의 경우, const를 기본으로, 재할당이 필요한 경우에만 let으로 선언하는 것이 좋다. 의도치 않은 재할당을 방지해주고, 재할당이 필요할 때는 변수의 스코프를 최대한 좁히는 것이 좋다.