변수명을 효율적이고 올바르게 선언하기 위해서는 전역 변수의 사용을 최소화하여야 한다. 즉, 최대한 변수의 사용 가능한 범위를 최소화 하는 것이 좋다.
poiemaweb.com/es6-block-scope#3-var-vs-let-vs-const
let, const | PoiemaWeb
ES5까지 변수를 선언할 수 있는 유일한 방법은 var 키워드를 사용하는 것이었다. var 키워드로 선언된 변수는 아래와 같은 특징이 있다. 이는 다른 언어와는 다른 특징으로 주의를 기울이지 않으면
poiemaweb.com
변수는 값의 위치(주소)를 기억하는 저장소이다. 값의 위치란 값이 위치하고 있는 메모리상의 주소를 의미한다.
즉, 변수란 값이 위치하고 있는 메모리 주소에 접근하기 위해 사람이 이해할 수 있는 언어로 명명한 식별자이다.
변수는 프로그램에서 사용되는 데이터를 일정 기간 동안 기억하여 필요한 때에 다시 사용하기 위해 데이터에 고유의 이름인 식별자를 명시한 것이다.
변수에 명시한 고유한 식별자를 변수명이라 하고 변수로 참조할 수 있는 데이터를 변수값이라 한다.
JavaScript ES5까지는 var 키워드를 통해서만 변수를 선언할 수 있었다.
그러나 ES6부터는 let 과 const 키워드를 통해 변수를 선언할 수 있고 변수의 사용 가능 범위를 최대한 좁히기 위해서는 var 변수보다 let 과 const 키워드를 사용해서 변수를 선언하는 것이 좋다.
변수는 var, let, const 키워드를 사용하여 선언하고 할당 연산자를 사용해 값을 할당한다.
* 동적 타이핑(Dynamic Trping)
JavaScript는 동적 타입 언어이므로 변수의 타입 지정없이 값이 할당되는 과정에서 자동으로 변수의 타입이 결정된다. 즉, 변수는 고정된 타입이 없다. 따라서 같은 변수에 여러 타입의 값을 자유롭게 할당할 수 있다.
이를 동적 타이핑(Dynamic Trping)이라고 한다.
var, let, const 키워드 별 특징을 알아보자.
- Function level scope / Block level scope
var | let, const |
함수 레벨 스코프 (Function level scope) - 함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 블록 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 모두 지역변수이며, 함수 외부에서 선언한 변수는 모두 전역 변수이다. |
블록 레벨 스코프 (block level scope) - 블록 레벨 스코프를 가지면 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. |
함수의 코드 블록만을 스코프로 인정하게 되면 함수 블록 바깥에 있는 변수는 모두 전역변수가 되기 때문에 전역변수를 남발할 가능성이 높다.
블록 레벨 스코프에서는 블록 안에서 선언된 변수를 블록 외부에서 참조할 수 없지만, 함수 레벨 스코프는 블록 외부에서도 블록 내부에서 선언된 변수에 접근할 수 있게 된다.
- 키워드 생략 허용 여부, 변수 중복 선언 허용 여부
var | let, const |
키워드 생략 가능 | 키워드 생략 불가능 |
변수 중복 선언 가능 | 변수 중복 선언 불가능 |
var a = 1;
var a = 10; // 중복 선언 가능
console.log(a); // 10
a = 100; // 재할당 가능
b = 10; // 키워드 생략 가능
let b = 2;
console.log(b); // 2
let b = 20; // 중복 선언 불가능
b = 20; // 재할당 가능
const c = 3;
console.log(c); // 3
const b = 30; // 중복 선언 불가능
b = 30; // 재할당 불가능
- 변수 생성 과정
그래서 프로그램이 실행되면 실행 컨텍스트(Execution Context)가 생성되고 자바스크립트는 실행에 필요한 여러 정보들을 담을 객체를 생성한다.
이를 Variable Object라고 한다.
1. 선언단계(Declaration phase) - Variable Object에 변수를 등록한다. - 이 단계에서 scope가 변수를 참조할 수 있다. |
2. 초기화 단계(Initialization phase) - Variable Object에 등록된 변수를 메모리에 할당한다. (변수를 위한 공간을 메모리에 확보한다.) - 이 단계에서 변수는 undefined로 초기화된다. |
3. 할당 단계(Assignment phase) - undefined로 초기화 된 변수에 실제 값을 할당한다. |
var 키워드로 생성된 변수는 Declaration phase와 Initialization phase가 한번에 이루어진다.
즉, 스코프에 변수를 등록하고 메모리에 변수를 위한 공간을 할당하며 undefined로 초기화되는 과정이 동시에 일어나고 그 이후에 변수에 값을 할당한다.
따라서 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하고 초기화된 상태이므로 에러가 발생하지 않는다. (값이 undefined 로 출력된다.)
-> 이를 호이스팅이라고 한다.
* 호이스팅이란 변수 선언문, 함수 선언문이 해당 scope의 최상단으로 끌어올려진 것 처럼 동작하는 특성을 말한다.
호이스팅이란?
let 키워드로 생성된 변수는 Declaration phase와 Initialization phase가 분리되어 진행된다.
프로그램이 실행되면 Variable Object에 변수가 등록되고 scope내에서 변수를 참조할 수 있게 되지만 변수가 메모리에 할당되고 초기화되는 과정은 변수의 선언문에 도달했을 때 이루어진다.
초기화되기 이전에(코드에서 변수의 선언문에 도달하기 전에) 변수에 접근하면 참조 에러(Reference Error)가 발생한다.
변수를 위한 메모리 공간이 아직 확보되지 않았기 때문이다.
따라서 스코프의 시작지점부터 변수가 선언되어 초기화되는 지점 사이에서는 변수를 참조할 수 없다.
이를 일시적 사각지대(Temporal Dead Zone; TDZ)라고 부른다.
* TDZ(Temporal Dead Zone) : let변수가 VO에 등록되어 스코프 내에서 변수를 인식할 수 없는 상태지만 아직 메모리 공간을 할당받지 못했고 초기화되지 않은 상태로 변수에 접근할 수 없는 상태이다.
결국 호이스팅이 발생하지 않는 것과 차이가 없어보인다.
하지만 그렇지 않다.
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: foo is not defined
let foo = 2; // 지역 변수
}
위 예제에서 변수 foo를 콘솔에 출력한 결과는 1도, 2도 아닌 참조 에러가 발생한다.
두 번째 foo 변수가 속한 블록 안에서 hoisting이 일어나 foo 변수가 블록 스코프 내에 '등록'되어있는 상태이기 때문이다.
그러나 참조에러가 나는 이유는 아직 선언문에 도달하지 않은 상태이므로 메모리에 공간을 할당받아 변수의 값이 초기화되기 이전이기 때문이다.
※ let 키워드와 const 키워드 모두 호이스팅이 일어난다.
나는 let 키워드가 블록을 투명한 막으로 둘러싸고 있다고 생각한다. 밖에서 전역 변수가 들어오거나 블록 내의 변수가 밖에서 사용되지 못하게 둘러싸고있어 블록 내에 존재하는 변수는 블록 내에서만 사용 가능하다.
그러나 직접 값이 선언되기 전에는 해당 변수를 위한 공간이 확보되지 않아 그 주소를 찾지 못해 나오는 참조에러가 발생하게 된다.
- 전역 객체(Global Object)
var 키워드는 전역 변수로 선언되면 전역 객체의 프로퍼티가 된다.
그러나 let 키워드는 전역 변수로 선언되어도 전역 객체의 프로퍼티가 아니다.
let 전역변수는 보이지 않는 개념적인 블록 내에 존재하게 된다.
const 키워드는 대부분 let 키워드와 특징이 동일하다.
const와 let의 차이점을 알아보자.
const 키워드는 변하지 않는 값(상수)을 위해 존재하는 키워드이다.
let은 재할당이 자유로우나 const는 재할당이 금지된다.
let foo = 4;
foo = 3; // 가능
const goo = 2;
goo = 4 ; // 불가능(Error)
주의해야 할 점은 선언과 동시에 할당이 이루어져야 한다는 것이다.
const foo;
foo = 5; // 불가능(Error)
그렇지 않으면 에러가 발생한다.
* 객체타입 변수를 선언할 땐 const 키워드!!
- const 키워드는 재할당이 불가능한 상수를 저장할 때 사용하기 좋은 키워드이다.
재할당이 불가능하다는 것은 객체에 대한 참조를 변경하지 못한다는 것을 뜻한다.
그러나 객체의 프로퍼티는 변경이 가능하다.
(프로퍼티 추가, 삭제, 프로퍼티 값 변경)
const grade = { eunbin: 80 };
grade = {} ; // 불가능(Error)
grade.eunbin = 100;
console.log(grade); // { eunbin: 100 }
'Programming > JavaScript' 카테고리의 다른 글
[javaScript] map 메소드 (0) | 2021.03.22 |
---|---|
[JavaScript] textContent / innerText / innerHTML (0) | 2021.03.16 |
[JavaScript] 배열(Array) (0) | 2021.03.10 |
[Javascript] DOM이란? | DOM의 선택자 | DOM tree | node vs element (0) | 2021.03.09 |
[JavaScript] Jasmine이란? 간단한 예제로 알아보기 (0) | 2021.03.05 |