JavaScript | 13장 스코프, 14장 전역 변수의 문제점, 15장 let, const 키워드와 블록 레벨 스코프

설탕·2024년 4월 17일
0

스코프

  • 스코프는 식별자가 유효한 범위이다.
  • 지역 변수는 자신의 지역 스코프와 하위 지역 스코프에서 유효하다.

스코프 체인

  • 스코프가 계층적으로 연결된 것을 스코프 체인이라 한다.
  • 모든 지역 스코프의 최상위 스코프는 전역 스코프다.
  • 변수를 참조할 때 자바스크립트 엔진은 스코프 체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다. 이를 통해 상위 스코프에서 선언한 변수를 하위 스코프에서도 참조할 수 있다.
  • 자바스크립트 엔진은 코드를 실행하기에 앞서 렉시컬 환경(Lexical Environment)를 실제로 생성한다. 변수 선언이 실행되면 변수 식별자가 렉시컬 환경에 key로 등록되고, 변수 할당이 일어나면 이 렉시컬 환경의 변수 식별자에 해당하는 값을 변경한다.

렉시컬 스코프

  • 동적 스코프: 함수가 호출되는 시점에 동적으로 상위 스코프를 결정한다.
  • 렉시컬 스코프(정적 스코프): 함수 정의가 평가되는 시점에 상위 스코프가 정적으로 결정된다.

자바스크립트는 렉시컬 스코프를 따르므로 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라 상위 스코프를 결정한다. 함수가 호출된 위치는 상위 스코프 결정에 아무런 영향도 주지 않는다. 즉, 함수의 상위 스코프는 언제나 자신이 정의된 스코프다.

함수 정의가 실행되어 생성된 함수 객체는 정적으로 결정된 상위 스코프를 기억한다. 함수가 호출될 때마다 함수의 상위 스코프를 참조할 필요가 있기 때문이다.

var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1

변수의 생명 주기

변수의 생명 주기는 메모리 공간이 할당된 시점부터 메모리 공간이 해제되어 가용 메모리 풀(memory pool)에 반환되는 시점까지다.

변수는 자신이 등록된 스코프가 소멸(메모리 해제)될 때까지 유효하다. 할당된 메모리 공간은 더 이상 그 누구도 참조하지 않을 때 가비지 콜렉터에 의해 해제되어 가용 메모리 풀에 반환된다.

전역 변수의 호이스팅 vs 지역 변수의 호이스팅

💡 호이스팅은 스코프를 단위로 동작한다.

  • 전역 변수의 호이스팅: 전역 변수의 선언이 전역 스코프의 선두로 끌어 올려진 것처럼 동작한다.
  • 지역 변수의 호이스팅: 지역 변수의 선언이 지역 스코프의 선두로 끌어 올려진 것처럼 동작한다.

전역 변수의 생명 주기

var 키워드로 선언한 전역 변수의 생명 주기는 전역 객체의 생명 주기와 일치한다.

전역 객체는 클라이언트 사이드 환경(브라우저)에서는 window, 서버 사이드 환경(Node.js)에서는 global 객체를 의미한다. 브라우저 환경에서 var 키워드로 선언한 전역 변수는 전역 객체 window의 프로퍼티가 되어 웹페이지를 닫을 때까지 유효하다.

전역 변수의 문제점

  • 암묵적 결합: 모든 코드가 전역 변수를 참조하고 변경할 수 있다.
  • 긴 생명 주기: 생명 주기가 길어 메모리 리소스도 오랜 기간 소비하고, 전역 변수의 상태를 변경할 수 있는 시간이 길고 기회가 많다.
  • 스코프 체인 상에서 종점에 존재: 변수를 검색할 때 전역 변수가 가장 마지막에 검색되므로 검색 속도가 가장 느리다.
  • 네임스페이스 오염: 파일이 분리되어 있어도 하나의 전역 스코프를 공유하므로 동일한 이름으로 명명된 전역 변수나 전역 함수가 있으면 예상치 못한 결과를 가져올 수 있다.

var, let, const 차이점

선언과 초기화

  • var 키워드로 선언한 변수는 중복 선언이 가능하다. 이때 중복되는 변수 선언문은 초기화문이 있으면 var 키워드가 없는 것처럼 동작하고 초기화문이 없으면 무시된다.

    var x = 1;
    var y = 1;
    
    var x = 100; // var 키워드가 없는 것처럼 동작한다.
    var y; // 무시된다.
    
    console.log(x); // 100
    console.log(y); // 1
  • let 키워드로 중복 선언하면 문법 에러(SyntaxError)가 발생한다.

  • var 키워드로 선언한 변수는 선언초기화가 한번에 진행된다. 선언 단계에서 스코프에 변수 식별자를 등록해 자바스크립트 엔진에 변수의 존재를 알리고(선언), undefined로 변수를 초기화한다.
    → 변수 선언문 이전에 변수에 접근해도 스코프에 변수가 존재하기 때문에 에러가 발생하지 않고, undefined를 반환한다.

  • let 키워드로 선언한 변수는 선언초기화가 분리되어 진행된다. 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 선언 단계가 먼저 실행되지만 초기화 단계는 변수 선언문에 도달했을 때 실행된다.
    → 초기화 단계가 실행되기 이전에 변수에 접근하려고 하면 참조 에러(ReferenceError)가 발생한다.

    TDZ(Temporal Dead Zone)
    : 스코프의 시작 지점부터 초기화 시작 지점까지 변수를 참조할 수 없는 구간

  • const 키워드로 선언한 변수는 반드시 선언과 동시에 초기화해야 한다.

재할당

  • var 또는 let 키워드로 선언한 변수는 재할당이 자유로우나 const 키워드로 선언한 변수는 재할당이 금지된다.

함수 레벨 스코프 vs 블록 레벨 스코프

  • var 키워드로 선언한 변수는 함수 레벨 스코프를 따른다.
    • 오로지 함수의 코드 블록만을 지역 스코프로 인정한다.
  • let 키워드로 선언한 변수는 블록 레벨 스코프를 따른다.
    • 모든 코드 블록(함수, if문, for문, while문, try/catch문 등)을 지역 스코프로 인정한다.

전역 객체

  • var 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 되지만 let, const 키워드로 선언한 전역 변수는 전역 객체의 프로퍼티가 아니다. let, const 전역 변수는 전역 렉시컬 환경의 선언적 환경 레코드 내에 존재하게 된다.

profile
공부 기록

0개의 댓글