[자바스크립트 토픽 정리] 변수 선언위치에 대해
변수는 메모리 저장방식부터 호이스팅까지 다양한 내용이 있다. 추가로 공부할 때마다 이 포스팅에 계속해서 업데이트할 예정!
변수에 대하여
🍊 계기
제로초 자스 강의 중 계산기 혼자서 구현하다가 변수 선언 오류 보고 의문. 함수 선언 위치와 변수 선언 위치가 어떻게 영향을 미치는지 궁금해짐!
🍊 노트
기본적으로 변수의 개념부터 알아보자.
변수는 왜 필요한가?
변수가 프로그래밍에서 필요한 이유는 값을 기억하고 활용하기 위해서다. 2000 - 1000의 연산을 했다고 가정해보자. 이 연산결과를 활용하고 싶다면 이 값을 어딘가 저장하고 필요할 때 불러올 수 있어야 한다.
또한, 변수를 선언하여 내가 저장하고자 하는 값에 이름이 붙지 않는다면 그 값을 참조하기가 어렵다. “참조”라는 건 뒤에서 다루겠지만 값이 저장되어있는 곳을 알고 그 값을 읽어올 수 있는 것이다. 그런데 운영체제마다 메모리 공간에 할당하는 방식이 다르며, 같은 운영체제나 컴퓨터라고 하더라도 프로그램 실행 시 메모리 사정에 따라 다르게 이루어질 수 있다.
변수는 어떻게 저장되는가?
메모리 공간에 대해
자바스크립트의 변수에 대해서는 기본적으로 2가지 절차가 있다. 변수의 “선언”과 “할당”이다. 이를 이해하려면, 변수가 메모리 상에서 어떻게 저장되는지 이해해야 한다.
var score;
위와 같은 코드를 실행했다고 가정하자.
자바스크립트 엔진은 해당 변수를 위한 메모리 공간을 확보하고, 그 메모리 공간의 주소를 참조할 수 있는 score라는 이름을 매핑해준다.
(내가 살고 있는 곳이 1004호라면, 1004호에 있는 값을 가져올 수 있는 이름인 “myHome”을 매핑해주는 것이다.)
- 식별자는 값이 아니라 ‘주소’를 기억한다.
- 변수와 값의 매핑 정보는 ‘실행 컨텍스트’에 등록된다. 이는 자바스크립트 엔진이 소스코드를 평가/실행하기 위한 환경을 제공하고 실행결과를 관리하는 곳이다.
식별자에 대해
갑자기 ‘식별자’라는 표현을 사용했다. 식별자는 값을 구별할 수 있게 만들어주는 고유한 이름을 뜻한다. 변수, 함수, 클래스 등의 이름은 모두 식별자다.
선언과 할당
변수를 선언하면 위에서 설명한 메모리 차원에서 공간을 확보하고 매핑하는 일이 이루어진다. 이때 해당 공간에 undefined라는 값이 자동으로 할당된다. 값이 비어있지 않은 것이다!
값을 할당하면, 해당 공간을 지우는 것이 아니라 새로운 메모리 공간을 확보하여 새로운 값을 넣어준다. 해당 변수명이 참조하는 공간이 달라지는 것. 아래 사진의 절차와 같다.
엄밀히 따지면, 자바스크립트의 경우 선언 후 특정 값을 처음 할당할 때도 이미 undefined라는 값이 채워져있다가 새로운 값을 넣는 것이므로 “재할당”에 해당한다. 이와 같은 이유로 위의 사진의 일이 발생하는 것.
호이스팅
var의 경우 선언은 런타임 전에, 할당은 런타임에 일어난다. 즉 한 줄씩 코드를 실행하기 전에, 자바스크립트 엔진이 소스코드를 평가하는 과정에서 미리 선언되는 것이다. 따라서 아래의 코드에서 변수 선언 전에 해당 값을 출력해보면, ReferenceError가 나지 않고 undefined값이 출력된다.
console.log(score); // undefined
var score;
score = 100;
console.log(score); // 100
이렇게 변수 선언문이 마치 코드의 맨 윗줄로 끌어올려져 실행되는 것과 같은 현상을 변수의 호이스팅(variable hoisting)이라고 한다.
✅정리: 이렇게 느껴질 수 있는 이유는, 선언을 런타임 전에 실행하고 동시에 undefined로 초기화하므로 소스코드의 순서상 선언이 더 뒤에 있어도 참조 에러가 나지 않는 것
그러나, 위의 개념 정리는 var 변수를 기준으로 한 것이므로 ES6에 더 적합한 let, const에 대하여 추가적으로 알아보겠다.
var의 문제점
var은 다른 프로그래밍 언어의 변수와는 달리 치명적인 몇 가지 문제점을 갖고 있다.
1. 중복 선언 허용
만약 값을 초기화하지 않고 중복 선언을 한다면 → 두 번째 선언을 무시한다. 그러나 에러는 나지 않는다. 값을 선언 시 초기화한다면 → 해당 값으로 덮어 씌워진다. 즉 변수가 의도치 않게 중복되면 잘못된 값이 할당될 수 있는 것인다
2. 함수 레벨 스코프
var키워드는 함수 코드 블록만 지역 스코프로 허용하여, 전역 변수가 남발될 수 있다. 반복문이나 조건문에서만 사용하고 싶어 선언한 변수도 의도치 않게 전역변수로 남게 되는 것이다.
3. 변수 호이스팅
var키워드는 선언 및 초기화가 런타임 전에 실행되므로, 선언문 이전에서도 참조할 수 있다. 다만 undefined가 반환되므로 의도되지 않은 방향으로 실행될 수 있다. 물론, let과 const키워드도 호이스팅이 일어나지만 그 방식이 var과 다르다. 이는 이후 다룰 예정.
let키워드의 등장
let키워드는 위에 서술한 var키워드의 문제점들을 보완하기 위해 등장하였다. var의 문제점들과 대응하여 그 특징들을 알아보면 더욱 이해하기 쉽다.
1. 중복 선언 금지
같은 변수를 한 번 더 선언할 경우, SyntaxError를 발생시킨다.
2. 블록 레벨 스코프
함수 코드 블록이 아니라 반복문, 조건문, try catch문 등 지역 소크프로 인정하는 블록 레벨 스코프 기준을 따른다
3. 변수 호이스팅
let키워드는 var와 달리 변수 호이스팅이 발생하지 않는 것처럼 동작한다. “않는 것처럼”이라는 뜻은 실제로는 호이스팅이 발생하긴 하지만, 겉으로 보이는 결과는 var와 다르다는 것이다. 차이는 아래와 같다.
let키워드는 런타임 이전에 변수 선언문을 실행하고, 초기화를 동시에 하지 않는다. 따라서 코드상의 선언문 전에 해당 변수를 참조하면 ReferenceError를 발생시킨다. 따라서 var과 달리 호이스팅이 발생하지 않는 것처럼 보이는 것이다.
let키워드는 코드 상의 선언문을 만났을 때, 초기화를 진행한다. 이때 스코프 시작 지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간을 TDZ(Temporal Dead Zone)일시적 사각지대라고 칭한다.
4. 선언하지 않은 변수에 값을 할당한 암묵적 전역에 대해 var키워드는 window의 프로퍼티가 되지만, let은 그렇지 않다.
let 전역 변수는 개념적인 블록 내에 존재하는데 이는 이후에 다룬다.
const 키워드에 대하여
const는 대부분의 사람들에게 ‘상수’를 위해 사용된다고 알려져 있다. 그러나 반드시 상수 선언을 위해서만 사용되는 것은 아니다. const는 대부분의 특징이 let과 유사하므로 다른 점을 기준으로 정리하겠다.
1. const키워드는 선언과 초기화를 반드시 동시에 해야 한다.
let과 동일하게 블록 레벨 스코프를 기준으로 동작하며, 변수 호이스팅이 발생하지 않는 것처럼 동작한다.
2. 재할당이 불가능하다.
재할당이 불가능하다는 것은 값을 바꾸는 것 자체가 아예 불가능하다는 의미는 아니다. 재할당 외의 방식으로 값을 수정하는 것은 가능하다. 가령, 객체 리터럴은 재할당하지 않고 프로퍼티에 접근하여 값을 수정할 수 있다.
🍊 Reference
모던 자바스크립트 딥다이브 4장 호이스팅 (p.34-49)
'프로그래밍 언어 > JavaScript' 카테고리의 다른 글
[프로그래머스 Lv.1] 개인정보 수집 유효기간 (자바스크립트) (1) | 2024.05.25 |
---|---|
[프로그래머스 Lv.0] 자바스크립트로 레벨0 모두 풀이하기 (0) | 2024.05.23 |
[자바스크립트 토픽 정리] 옵셔널 체이닝 ?. (0) | 2024.04.06 |
바닐라 자바스크립트로 숫자야구 만들기 (feat. 코딩자율학습 제로초) (0) | 2024.03.20 |
바닐라 자바스크립트로 계산기 만들기 (feat. 코딩자율학습 제로초) (1) | 2024.03.17 |