JS 키워드 정리 - var, let, const, 스코프, 호이스팅

Seuling·2022년 7월 6일
1

기술면접준비

목록 보기
1/4
post-thumbnail

키워드 정리

var let const

변수 선언

var

특징

  • 기존에 선언된 변수의 값을 덮어쓰며 함수 스코프를 기준으로 동작한다.
  • var로 변수를 선언할 경우 스코프 내에 이미 동일한 식별자를 가진 변수가 존재한다면 해당 변수에 값을 재할당한다.
  • 기존에 선언된 변수의 값을 덮어쓴다면 다른 코드에 영향을 주거나 버그가 발생할 때 원인을 찾기 어렵다.
  • 변수가 함수 스코프를 가진다는 것은 변수를 선언한 함수 몸체 안에서만 해당 변수에 접근할 수 있다는 의미
  • ES6이전 사용되던 방식으로, 글로벌 변수로 선언되기 때문에 프로그램 종료할 때 까지 메모리에 남아있게 된다.
var a = 1;
if (isSomething){
var a = 2;
}
console.log(a); //2

문제점

개발자의 실수로 예측하기 어려운 문제가 발생할 수 있다.

예측하기 어려운 문제의 예시는?
예를들면, for 반복문의 초기값으로 i를 선언하고, 반복문이 종료되면 변수 i에 접근할 수 없을 것 같지만, 함수의 실행이 종료되기 전까지 접근할 수 있다. 대부분 이런 접근은 불필요하며 혼란을 초래한다.
만약, 전역 스코프에 i라는 변수가 선언되었다면 값이 덮어씌워지는 문제 발생

let const

특징

  • 재선언을 허용하지 않으며 함수 스코프가 아닌 블록 스코프를 가진다. (재선언시? -> SyntaxError 발생)
  • 변수를 둘러싼 블록 ({})안에서만 해당 변수에 접근할 수 있다.

let const 차이?

  • let : 변수를 저장하는 유일한 키워드. 중괄호 {}로 구성된 코드블럭 안에서 사용하는 경우, 코드블럭이 끝나면 메모리가 해제되기 때문에 메모리 낭비가 일어나지 않는다.
  • const는 let과 달리 값의 변경을 허용하지 않는다. (값을 변경하면 ? -> TypeError발생)
  • const는 상수처럼 변하지 않는 값을 선언할 때 사용한다.

면접 질문

스코프

특징

  • 변수나 매개변수에 접근할 수 있는 범위를 결정한다.
  • 자바스크립트의 스코프는 함수와 블록 단위의 스코프로 나눌 수 있다.
  • 함수나 블록의 선언 위치에 따라 중첩된 스코프가 정의될 수 있다.

스코프 종류

  • 전역 스코프
    전역에서 접근할 수 있음
  • 지역 스코프
    해당 지역에서만 접근할 수 있음
  • 함수 스코프
    함수 몸체 안에서만 접근할 수 있음

함수 스코프와 블록 스코프

함수스코프와 var

  • 선언된 함수 단위로 생성되는 스코프이며, 함수 스코프 안에 선언된 변수나 함수들은 모두 함수 스코프에 포함된다.

블록스코프와 let, const

  • 변수의 유효 범위를 블록({})단위로 제한하여 사용할 수 있다.
  • const 키워드를 사용해 선언한 변수 a는 블록 안에서만 유효하며, 블록을 벗어나서는 접근할 수 없다.
  • 변수가 블록 스코프를 갖도록 선언하는것이 직관적이며 버그를 줄일 수 있다.

렉시컬 스코프

  • 동적 스코프 : 런타임 중 함수의 호출에 의해 결정
  • 렉시컬 스코프 : 변수나 함수를 어디에 작성하였는가에 기초하여 결정
  • 자바스크립트 및 대부분 프로그래밍 언어들을 렉시컬 스코프 규칙을 따르고 있다.

스코프 체이닝

  • 중첩된 스코프 내에서 코드가 실행된 경우, 가장 안쪽의 스코프부터 시작하여 상위 스코프로 올라가며 원하는 대상을 검색한다.
  • 대상을 찾는 즉시 검색을 중단한다.
  • 안쪽부터 상위로 올라가며 검색하기 때문에, 상위 스코프에서 안쪽 스코프의 변수나 함수에는 접근할 수 없다.

함수 스코프 & 블록 스코프 : 스코프의 단위
렉시컬 스코프 : 스코프들의 범위를 결정하는 규칙

호이스팅

  • 선언문이 스코프 내의 가장 최상단으로 끌어올려지는 것 의미
  • 선언이 코드 실행 보다 먼저 메모리에 저장되는 과정으로 인한 현상
  • 선언문은 항시 자바스크립트 엔진 구동시 가장 최우선으로 해석하므로 호이스팅 되고, 할당 구문은 런타임 과정에서 이루어지기 때문에 호이스팅 되지 않는다.

변수 생성 과정

  • 선언 : 스코프에 변수를 선언
  • 초기화 : 변수의 값을 undefined로 초기화하며, 실제로 변수에 접근 가능한 단계
  • 할당 : 할당문을 만나면 변수에 실제 값을 할당함.

var 변수 선언

  • 선언과 초기화 단계를 한번에 실행
  • 이 두단계가 스코프의 최상단으로 끌어올려져 실행됨. 따라서 선언하기 전 변수에 접근하여도 이미 초기화가 되어 접근이 가능한 것
var a;
console.log(a) //undefined
a =1

let const 변수 선언

  • 선언과 초기화 단계가 분리되어 실행
    선언 : 스코프의 최상단으로 끌어올려져 실행되지만, 초기화 단계는 선언문을 만나면 실행됨
    초기화 단계 이전에 변수 접근하면 ? -> ReferenceError발생

Temporal Dead Zone (TDZ)

선언 단계가 실행되는 스코프의 최상단부터 초기화 단계를 실행하는 선언문이 나오기 전까지는 변수에 접근할 수 없다.

TDZ
선언
TDZ
초기화
할당

면접 예상 질문

👤 : var, let const에 대해 설명해주세요.

let과 const는 ES6에서 추가된 문법이다. 자바스크립트 변수 선언은 선언 → 초기화 단계로 수행됩니다.

  • var: var 키워드는 선언과 초기화가 동시에 이루어져 undefined를 할당하여 초기화한다.
    • 변수 중복 선언이 가능하여 예기치 못한 값을 반환할 수 있다.
    • 함수 외부에서 선언한 변수는 모두 전역변수가 된다.
    • 변수 선언문 이전에 변수를 참조하면 언제나 undefined를 반환한다.
  • let: let 키워드로는 변수 중복 선언이 불가하지만, 재할당은 가능하다.
  • const: const가 let과 다른 점이 있다면 반드시 선언과 할당을 동시에 해주어야합니다. (재할당 불가)

💡 letconst 모두 블록레벨 스코프를 따른다. 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)에 빠지기 때문이다.

reference

[JavaScript] 호이스팅(Hoisting)이란?

JavaScript 모의면접 질문 리스트

TDZ(Temporal Dead Zone)를 통해 밝혀진 let과 const의 호이스팅(hoisting)

profile
프론트엔드 개발자 항상 뭘 하고있는 슬링

0개의 댓글