Scope

스코프란 유효범위를 뜻한다. (변수가 유효한 범위)

  • 스코프는 참조 대상 식별자를 찾기 위한 규칙이고, 자바스크립트는 이 규칙을 따른다.
  • 대부분의 프로그래밍 언어에서는 블록 레벨 스코프를 따른다.
  • 그러나, 자바스크립트에서는 함수 레벨 스코프를 따른다.

ES6의 let, const를 사용하면 블록 레벨 스코프를 사용할 수 있다.

1. 전역 스코프와 지역 스코프

전역 스코프

  • 스코프는 계층적이며 트리의 맨 아래에 루트가 필요하다.
  • 프로그램 시작 시 암시적으로 주어지는 기본 스코프를 전역 스코프라 하며 코드 어디서든 참조가 가능하다.
  • 전역 변수는 전역 스코프를 가지고 전역 객체(window)의 프로퍼티이다.

지역 스코프 or 함수 스코프(Local Scope or Function-level Scope)

함수 코드 블록이 만든 스코프로 함수 자신과 하위 함수에서만 참조할 수 있다.

2. 전역 변수와 지역 변수

변수는 선언 위치에 따라서 스코프를 가진다.

전역 변수

전역에서 선언된 변수이며 어디에서든 참조할 수 있다.

암묵적 전역 변수와 Strict 모드
  • 암묵적 전역변수(implicit global) : var 키워드를 생략한 변수는 암묵적으로 전역변수가 된다.
    • 개발자가 의도하지 않은 암묵적 전역변수는 오류 발생의 원인이 된다.
  • 스트릭트 모드(strict mode) : ES5 자바스크립트에서 사용하는 암묵적 전역 변수를 막기 위한 모드이다.
    • 주로 코드 전체를 즉시실해 함수로 감싸는 기법을 사용하여 적용한다.
    • 이유는 전역에 스크릭트 모드를 적용하면 내가 작성하지 않은 곳에서 에러가 발생할 수 있기 때문이다.
전역 변수와 즉시실행함수(IIFE)
  • 전역 변수 사용을 억제하기위해 즉시 실행 함수를 사용할 수 있다.
  • IIFE를 사용하면 전역 변수를 만들지 않으므로 라이브러리등에서 많이 사용된다.(JQuery등)
  • 즉, 캡슐화가 용이하다. 모듈 패턴이라고도 한다.
(function() {
  //IIFE Body
})();

지역 변수

함수 내에서 선언된 변수이며 그 지역과 하부 지역에서만 참조할 수 있다.

3. 정적 스코프(Lexical Scope)와 동적 스코프(Dynamic Scope)

정적 스코프

  • 함수가 선언될 때 생성되는 스코프로 대부분의 프로그래밍 언어와 자바스크립트도 정적 스코프를 따른다.
  • 함수가 어디서 선언되었는지에 따라서 스코프가 결정된다.
  • 자바스크립트의 정적 스코프는 전역 스코프, 블록 스코프, 함수 스코프에 적용된다.
var num = 100;
function foo() {
  var num = 10;
  console.log(`foo : ${num}`);
  bar();
}
function bar() {
  console.log(`bar : ${num}`);
}
foo();
//foo : 10
//bar : 100

foo 함수 호출 시 내부에서 bar가 호출되는 때에 x는 10이다. 그럼에도 100이 출력되는 것은 자바스크립트가 정적 스코프를 따르기 때문이다.

동적 스코프

  • 함수가 호출될 때 생성되는 스코프이다.
  • 함수가 어디서 호출되었는지에 따라서 스코프가 결정된다.
  • 프로그램의 런타임이나 실행 컨텍스트, 호출 컨텍스트에 의해 결정되는 스코프이다.

4. var과 let의 스코프(함수 레벨 스코프와 블록 레벨 스코프)

자바스크립트는 기본적으로 함수 레벨 스코프를 따른다. 즉, 블록 레벨 스코프를 사용하지 않는다. 그러나 ES6의 let, const는 블록 레벨 스코프를 사용한다.

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

  • 함수 레벨 스코프 : 함수 코드 블록이 만든 스코프는 함수 자기 자신과 그 함수의 하위 함수들 에서만 사용할 수 있다.
  • 블록 레벨 스코프 : 자바스크립트가 아닌 대부분의 프로그래밍 언어에서 사용하는 스코프로 모든 코드 블록(if, 함수, while, for, 일반 블록 등) 내에서 선언된 변수는 코드 블록내에서만 유효하다.
  • var : 함수 레벨 스코프를 가지고, 현재 스코프 안이라면 어디서는 사용할 수 있다.
    • 선언 전에도 사용할 수 있다.
    • var 변수는 호이스팅 메커니즘을 따른다.

호이스팅 ? 선언이 스코프의 맨위로 당겨지는 메커니즘(자세한 설명은 다음 포스팅인 실행 컨텍스트와 스코프체인에서 하도록 하겠습니다.)

  • let, const : 블록 레벨 스코프를 사용한다.
  • 특징
  1. let과 const 키워드로 선언된 변수는 동일 이름으로 중복 선언할 수 없다.
  2. 자바스크립트는 let과 const를 포함한 var, function등 모든 선언을 호이스팅한다.
    • 그러나 var와 달리 let으로 선언된 변수를 선언 전에 사용하려 하면 참조 에러가 발생한다.
    • 이유는 let 변수는 스코프 시작 부분부터 실제 변수의 선언까지 일시적 사각지대(Temporal Dead Zone)에 빠진다.

TDZ ? var 변수는 선언 단계와 초기화 단계가 스코프 시작에서 하는 반면 let은 선언만 하고 초기화 단계는 할당 단계에 이루어진다. 이 선언과 초기화 사이의 구간을 TDZ라 한다.

  1. let은 전역 변수가 아니다.(전역 개체의 프로퍼티가 아니다.)
  • let으로 전역 스코프에 선언을 하면 전역 변수로는 사용할 수 있지만 전역 객체의 프로퍼티가 되지는 않는다.

참고

  • Learning Javascript
  • Inside Javascript
  • https://poiemaweb.com/js-scope#7-렉시컬-스코프
  • https://poiemaweb.com/es6-block-scope