# 변수
- 메모리 : 데이터를 저장할 수 있는 메모리 셀의 집합체.
각 셀은 고유한 메모리 주소를 갖는다. 이 메모리 주소는 '메모리 공간의 위치'를 나타낸다.
메모리 주소를 통해 데이터에 직접 접근하는 것은 치명적 오류를 발생시킬 가능성이 높은, 매우 위험한 일이다.
만약 실수로 운영체제가 사용하고 있는 값을 변경하면 시스템을 멈추게 할 수 있는 치명적인 오류를 발생시킬수 있기때문에, 자바스크립트는 직접적으로 메모리를 제어하는것을 허용하지 않는다.
그래서 자바스크립트는 값을 메모리에 저장하고, 저장된 값을 읽어 들여 재사용하기위해서 '변수'를 사용한다.
- 변수 : 메모리 공간을 식별하기 위해 붙인 이름. 즉 값의 위치를 가리키는 이름.
ex: 변수 'score'는 값 90이 저장되어 있는 메모리 주소 0x0669F913을 기억해야한다. 즉, 변수는 값이 저장되어있는 메모리 주소와 매핑 관계를 맺으며, 이 매핑 정보도 메모리에 저장되어야 한다.
변수 이름을 사용해 참조를 요청하면, 자바스크립트 엔진은 변수 이름과 매핑된 메모리 주소를 통해서 메모리 공간에 접근해서 저장된 값을 반환한다.
(변수에 저장된 값을 읽어 들이는 것 : 참조)
Q. 변수에 값을 할당하는건 메모리를 직접 제어하는게 아닌가요?
var score;
score = 80;
score = 90;
변수에 값을 할당하거나, 재할당할때는 이전 값이 저장되어있던 메모리 공간을 지우고 그 메모리 공간에 새로운 값을 저장하는게 아니라, 새로운 메모리 공간을 확보하고 그곳에 할당값을 저장하고, score라는 변수에 새롭게 저장된 값의 메모리 주소를 저장한다.
현재 score 변수의 값은 90.
score변수의 이전 값인 undefined, 80은 어떠한 변수와도 연결이 되어 있지 않다. 이건 undefined, 80이 더이상 필요하지 않다는 것을 의미.
이러한 불필요한 값들은 가비지 콜렉터에 의해서 메모리에서 자동으로 해제된다. (해제 시기는 예측할 수 없다.)
메모리 공간을 주기적으로 점검해서 더이상 사용되지 않는 메모리를 해제한다.
자바스크립트 엔진은 변수 생성을 3단계에 거쳐 수행한다.
1/ 선언단계 : 스코프에 변수를 등록하고, 자바스크립트 엔진에게 변수의 존재를 알린다. 변수를 선언할때는 var, const, let 키워드를 사용한다.
** 스코프(scope) : 식별자(ex. 변수명, 함수명, 클래스명 등)의 유효범위
2/ 초기화단계 : 값을 저장하기 위한 메모리 공간을 확보하고, 암묵적으로 undefined를 할당해 초기화.
(초기화 : 변수가 선언된 후, 최초로 값을 할당하는 것을 말한다.)
3. 할당 단계 : undefined으로 초기화된 변수에 실제 값을 할당한다.
# 변수 호이스팅
- 실제 코드의 위치는 변하지 않지만, 브라우저가 JS를 해석할때 '변수 선언'을 스코프 내의 최상단으로 끌어올리는것처럼 동작하는 자바스크립트 고유의 특징.
console.log(score); //undefined
var score; //변수 선언문
위 코드를 보면, 변수 선언문보다 변수 참조하는 코드가 더 앞에 있다.
자바스크립트 코드는 인터프리터에 의해 한줄씩 순차적으로 실행되므로 console.log(score)가 가장 먼저 실행되고, 순차적으로 다음 줄에 있는 코드를 실행한다.
하지만, 변수 선언은 소스코드가 한줄씩 순차적으로 실행되는 시점이 아니라, 그 이전 단계에서 먼저 실행된다.
자바스크립트 엔진은 소스코드를 한줄씩 순차적으로 실행하기에 앞서 먼저 '소스코드의 평가 과정'을 거치면서 소스코드를 실행하기 위한 준비를 한다.
'소스코드의 평가과정'에서 자바스크립트 엔진은 변수 선언을 포함한 모든 선언문(변수선언문, 함수 선언문 등)을 소스코드에서 찾아내 스코프에 등록 → 소스코드의 평가과정 후, 비로소 변수 선언을 포함한 모든 선언문을 제외한 나머지 소스코드를 한줄씩 순차적으로 실행.
따라서, 자바스크립트 엔진은 변수 선언이 소스코드의 어디에 있든 상관없이 다른 코드보다 먼저 실행한다.
# var vs let vs const 비교
var
1/ 변수 선언 시, 선언단계와 초기화 단계가 '동시에 진행'되므로 확보된 메모리공간에 자바스크립트 엔진에 의해 'undefined'라는 값이 암묵적으로 할당되어 초기화된다.
//이미 여기서 선언단계 & 초기화 단계
//var score = undefined; 이렇게 변수 선언이 스코프 최상단에 끌어올려진것처럼 된다.
console.log(score); //undefined
var score; //변수 선언문
2/ 변수 중복 선언 허용
var키워드로 선언한 변수는 중복 선언이 가능하다.
var x = 1;
var y = 1;
var x = 100;//var키워드로 선언된 변수는 같은 스코프 내에서 중복 선언을 허용한다.
//중복선언 시, 초기화문(선언,초기값 할당 동시)이 있는 변수 선언문은 자바스크립트 엔진에 의해 var키워드가 없는 것처럼 동작한다.
//x = 100;
var y; //초기화문이 없는 변수 선언문은 무시된다.
console.log(x);//100
console.log(y);//1
- 문제점 : 만약 동일한 변수가 이미 선언되어있는것을 모르고 변수를 중복선언하고 값까지 할당했다면 먼저 선언된 변수 값이 변경되는 부작용.
3/ 블록 레벨 스코프를 지원 x. 함수 레벨 스코프만 지원.
즉, 오로지 '함수코드블록'만을 지역 스코프로 인정. 함수 외부에서 var키워드로 선언한 변수는 블록 내에서 선언해도 전역 변수가 된다.
var x = 1;
if(true) { //함수 코드x. if문 내의 x는 전역변수.
var x = 10; //x는 이미 전역변수가 있다. 중복선언이다.
}
console.log(x);// 10
let
1/ let 키워드로 선언한 변수도 '당연히' 호이스팅 된다.
- 하지만, '선언단계'와 '초기화 단계'가 분리되어 진행.
// 호이스팅이 일어나 '선언단계' 실행o. '초기화단계'x.
console.log(foo);// ReferenceError:foo is not defined
let foo;// 이제서야 '초기화 단계' // foo = undefined;
let 키워드로 변수 선언을 함으로써 소스코드 실행 전인 '소스코드 평가과정'에서 변수 '선언단계' 실행.
let 키워드로 선언한 변수를 변수 선언문 이전에 참조하면 참조 에러가 발생한다.
why?
→ 소스코드 실행 이전에 '선언 단계'가 먼저 실행되지만 '초기화 단계'는 변수 선언문에 도달했을 때 실행된다.
초기화 단계가 실행되기 이전에 변수에 접근하려고 하면, '참조 에러'가 발생.
let 키워드로 선언한 변수는 선언단계부터 초기화 단계 시작 지점(변수 선언문)까지 변수를 참조할 수 없다. 이 구간을 '일시적 사각 지대(Temporal Dead Zone)이라고 부른다.
변수를 위한 메모리 공간이 아직 확보가 되지 않았기 때문.
//런타임 이전에 '선언단계' 실행. 하지만 아직 변수가 초기화 되지 않음
//초기화 이전까지 'TDZ'에서는 변수 참조 불가능
console.log(foo); // Reference Error
let foo; // 변수선언문에서 '초기화 단계' 실행
console.log(foo);// undefined
foo = 1; //값 할당
console.log(foo);//1
Q. 호이스팅이 일어나는건 맞는건지?
let foo = 1; // 전역변수
{
console.log(foo); //만약, 호이스팅이 발생하지 않는다면, 전역변수 1이 출력된다.
//하지만 호이스팅이 발생하기 때문에 ReferenceError발생
let foo = 2;
}
2/ 변수 중복 선언 금지
var키워드로 선언한 변수는 중복 선언이 가능하다. 하지만, let키워드로 이름이 같은 변수를 중복 선언하면 문법 에러가 뜬다.
let name = 'ria';
let name = 'jun'; // SyntaxError
3/ 블록 레벨 스코프
let 키워드로 선언한 변수는 모든 코드 블록(함수, if문, for문, while문 등)을 지역스코프로 인정하는 블록 레벨 스코프를 따른다.
let foo = 1;
{
let foo = 2;
let bar = 3;
}
console.log(foo);// 1;
console.log(bar);// ReferenceError: bar is not defined;
const
1/ 반드시 선언과 동시에 할당을 해야한다.
만약 그렇지 않으면 다음과 같은 문법 에러가 발생!
Q. const도 호이스팅이 일어나는가?
const foo = 1; // 전역변수
{
console.log(foo); //만약, 호이스팅이 발생하지 않는다면 전역변수 1이 출력된다.
//하지만 호이스팅이 발생하기 때문에 ReferenceError발생
const foo = 2;
}
호이스팅 시, 선언만 하고 아직 초기화를 하지 않기 때문에 let과 마찬가지로 변수 선언 이전에 접근 불가능하다.(TDZ)
2/ 재할당 금지
var, let 키워드로 선언한 변수는 재할당이 자유롭다. 하지만 const 키워드로 선언한 변수는 재할당 금지.
하지만, const 키워드로 선언된 변수에 객체를 할당한 경우, 값을 변경할 수 있다.
'JavaScript' 카테고리의 다른 글
[JS] 연산자 - 산술연산자 (0) | 2023.04.27 |
---|---|
유사배열객체(array-like object) (0) | 2023.04.19 |
스코프 checkpoint 문제 (0) | 2022.03.04 |
SPA란? (0) | 2022.02.21 |
part3 (0) | 2021.09.21 |