변수 선언
var a = 1;
if (isSomething){
var a = 2;
}
console.log(a); //2
개발자의 실수로 예측하기 어려운 문제가 발생할 수 있다.
예측하기 어려운 문제의 예시는?
예를들면, for 반복문의 초기값으로 i를 선언하고, 반복문이 종료되면 변수 i에 접근할 수 없을 것 같지만, 함수의 실행이 종료되기 전까지 접근할 수 있다. 대부분 이런 접근은 불필요하며 혼란을 초래한다.
만약, 전역 스코프에 i라는 변수가 선언되었다면 값이 덮어씌워지는 문제 발생
함수 스코프 & 블록 스코프 : 스코프의 단위
렉시컬 스코프 : 스코프들의 범위를 결정하는 규칙
var a;
console.log(a) //undefined
a =1
선언 단계가 실행되는 스코프의 최상단부터 초기화 단계를 실행하는 선언문이 나오기 전까지는 변수에 접근할 수 없다.
TDZ |
---|
선언 |
TDZ |
초기화 |
할당 |
👤 : var, let const에 대해 설명해주세요.
let과 const는 ES6에서 추가된 문법이다. 자바스크립트 변수 선언은 선언 → 초기화
단계로 수행됩니다.
var
: var
키워드는 선언과 초기화가 동시에 이루어져 undefined
를 할당하여 초기화한다.let
: let 키워드로는 변수 중복 선언이 불가하지만, 재할당은 가능하다.const
: const가 let과 다른 점이 있다면 반드시 선언과 할당을 동시에 해주어야합니다. (재할당 불가)💡 let
과 const
모두 블록레벨 스코프를 따른다. TDZ(Temporal Dead Zone)
구간에 들어가 선언은 되어있지만 아직 초기화가 되지않아 변수에 담길 값을 위한 공간이 메모리에 할당되지 않은 상태이기 때문에, not defined
라는 에러를 반환한다.
👤 : 변수 생성 과정에 대해 설명
A. 변수 생성 과정은 선언 단계(Declaration phase) => 초기화 단계(Initialization phase) => 할당 단계(Assignment phase) 이렇게 총 세 단계를 거쳐 생성되는데, var로 선언된 변수는 선언 단계에서 undefined를 할당하는 과정(초기화 과정)이 한 번에 진행되어서 변수 선언 전 호이스팅이 가능하지만, let은 선언 단계에서 초기화 과정(메모리 공간 확보)이 이루어지지 않기 때문에 선언 이전에 변수를 참조할 수 없다.
👤 : scope에 대해 알려주세요
A. 자바스크립트 엔진이 참조하는 식별자를 검색할 때 사용하는 규칙이다. 즉, 어떤 변수를 참조하거나, 함수를 호출할 때 해당 식별자를 찾아내는 메커니즘이다.
A. 스코프는 참조 대상 식별자(identifier, 변수, 함수의 이름과 같은 대상을 다른 대상과 구별하여 식별할 수 있는 유일한 이름)를 찾아내기 위한 규칙이다. 변수는 전역 또는 코드 블록(if, for, while, try/catch 등)이나 함수 내에 선언하며 코드 블록이나 함수는 중첩될 수 있다. 식별자는 자신이 어디에서 선언됐는지에 의해 유효한(다른 코드가 자신을 참조할 수 있는) 범위를 갖는다.
자바스크립트에서 스코프는 전역 스코프와 지역 스코프로 구분할 수 있다. 지역 스코프는 함수 코드 블록이 만든 스코프이다.
변수는 전역 변수와 지역 변수로 구분할 수 있다. 지역 함수는 함수 내에서 선언된 변수이다.
👤 : 렉시컬 스코프란 무엇인가?
함수를 어디서 호출하는지가 아니라, 함수가 어디에 선언되었는지에 따라 결정되는 스코프를 말한다.
자바스크립트 엔진은 스코프 체인을 통해 렉시컬 스코프를 파악한다.
자바스크립트는 렉시컬 스코프를 따르기에 함수를 선언한 시점에 상위 스코프가 결정된다.
👤 : 스코프체인은 무엇인가?
스코프체인은 전역 객체와 중첩된 함수의 스코프를 차례로 저장하고 있는 일종의 리스트이다. 객체의 프로퍼티가 아닌 식별자 즉, 변수를 검색하는 메커니즘이다.
👤 : let 키워드 사용 시 참조에러가 발생하는 이유는 ?
A. var 키워드로 선언된 변수와는 달리 let 키워드로 선언된 변수를 선언문 이전에 참조하면 참조 에러(ReferenceError)가 발생한다.
이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 *일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문이다.
여기서 중요한 지점은 이 호이스팅이라는 용어가 ‘선언이 먼저 메모리에 저장되었다.’는 것을 의미하기 때문에 즉, ‘선언이 끌어올려진다’는 의미이기 때문에 모든 선언은 호이스팅이 일어난다는 말은 참이된다.
즉, 호이스팅이 파일의 맨 위로 끌어올려진 것 같은 현상을 의미할 때 선언문 이전에 참조해서 에러를 발생시킨다고 호이스팅이 일어나지 않은 것은 아니라는 의미이다.
그런데 왜 오류가 나는가 하면 var 키워드는 선언과 함께 undefined로 초기화되어 메모리에 저장되는데 let과 const는 초기화되지 않은 상태로 선언만 메모리에 저장되기 때문이다.
초기화 되지 않으면 변수를 참조할 수 없다. 그래서 참조 에러를 일으키는 것이다.
👤 : 호이스팅이란?
(hoisting)이란, 인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다. var
로 선언한 변수의 경우 호이스팅 시 undefined
로 변수를 초기화한다. 반면 let
과 const
로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다.
👤👤 : 호이스팅 - 컴파일 언어와 인터프리터 언어가 뭐지?
컴파일러(compiler)
- 전체 파일을 스캔하여 한꺼번에 번역한다.
- 초기 스캔시간이 오래 걸리지만, 한번 실행 파일이 만들어지고 나면 빠르다.
- 기계어 번역과정에서 더 많은 메모리를 사용한다.
- 전체 코드를 스캔하는 과정에서 모든 오류를 한꺼번에 출력해주기 때문에 실행 전에 오류를 알 수 있다.
- 대표적인 언어로 C, C++, JAVA 등이 있다.
인터프리터(interpreter)
- 프로그램 실행시 한 번에 한 문장씩 번역한다.
- 한번에 한문장씩 번역후 실행 시키기 때문에 실행 시간이 느리다.
- 컴파일러와 같은 오브젝트 코드 생성과정이 없기 때문에 메모리 효율이 좋다.
- 프로그램을 실행시키고 나서 오류를 발견하면 바로 실행을 중지 시킨다. 실행 후에 오류를 알 수 있다.
- 대표적인 언어로 Python, Ruby, Javascript 등이 있다.
👤 : 변수는 어떻게 생성되며, 호이스팅은 어떻게 이뤄질까?
A. 변수는 3단계에 걸쳐 생성된다.
1단계: 선언 단계(Declaration phase)
변수를 실행 컨텍스트의 변수 객체에 등록한다.
이 변수 객체는 스코프가 참조하는 대상이 된다.
2단계: 초기화 단계(Initialization phase)
변수 객체에 등록된 변수를 위한 공간을 메모리에 확보한다.
이 단계에서 변수는 undefined로 초기화 된다.
3단계: 할당 단계(Assignment phase)
undefined로 초기화된 변수에 실제 값을 할당한다.
var 키워드로 선언한 변수는 선언 단계와 초기화 단계가 한번에 이뤄진다. 즉, 스코프에 변수를 등록(선언 단계)하고 메모리에 변수를 위한 공간을 확보한 후, undefined로 초기화한다. 따라서 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다. 다만 undefined를 반환한다. 이후 변수 할당문에 도달하면 비로소 값이 할당된다.
let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행된다. 즉, 스코프에 변수를 등록(선언 단계)하지만 초기화 단계는 변수 선언문에 도달했을 때(코드 실행 후) 이뤄진다. 초기화 이전에 변수에 접근하려고 하면 참조 에러가 발생한다. 이는 아직 변수가 초기화되지 않았기 때문이다. 즉, 변수를 위한 메모리 공간이 아직 확보되지 않았기 때문이다. 따라서 스코프의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없다. 스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 ‘일시적 사각지대(Temporal Dead Zone; TDZ)’라고 부른다.
👤 : Q5. 호이스팅과 Temporal Dead Zone이 어떻게 연관되어있는지 설명
자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, class)을 호이스팅한다.
호이스팅이란, 임의의 선언문을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성을 말한다. var 키워드로 선언된 변수는 선언 단계와 초기화 단계가 한 번에 이루어지기 때문에, 변수 선언문 이전에 변수에 접근하여도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않는다.
하지만, 블록 레벨 스코프인 let keyword로 선언된 변수는 선언문 이전에 참조 시, 참조 에러(ReferenceError)가 발생한다. 이는 let 키워드로 선언된 변수는 스코프의 시작에서 변수의 선언까지 일시적 사각지대(Temporal Dead Zone; TDZ)에 빠지기 때문이다.