변수의 유효 범위

2 minute read


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

대부분의 프로그래밍 언어는 블록 레벨 스코프를 따르지만 자바스크립트는 함수 레벨 스코프를 따른다.

  • 함수 레벨 스코프
    함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.

    // 전역 변수
    var x = 10;
    
    function func() {
      // 지역 변수
      var x = 20;
    }
    
    console.log(x);
    // 함수 레벨 스코프로 10이 출력된다.
    
    // --------------------------------
      
    // 전역 변수
    var x = 10;
    
    {
      // 전역 변수
      var x = 20;
    }
    
    console.log(x);
    // 20 출력
    
  • 블록 레벨 스코프
    모든 코드 블록(함수, if, for, while 등) 내에서 선언된 변수는 코드 블록 내에서만 유효하며 코드 블록 외부에서는 참조할 수 없다. 즉, 코드 블록 내부에서 선언한 변수는 지역변수이다.

    // c++
    int x = 10;
    
    {
      int x = 20;
    }
    
    printf("%d", x);
    // 10 출력
    


var

변수를 선언하기 위해서 사용하는 키워드이다.

var 특징

  • 함수의 코드 블록만을 유효 범위(scope)로 인정하기 때문에 전역 함수 외부에서 생성한 변수는 모두 전역 변수이다.

  • var키워드는 생략이 가능하기 때문에 암묵적 전역 변수를 양산할 가능성이 크다.

  • 변수의 중복 선언이 허용되기 때문에 의도하지 않은 변수값의 벼경이 일어날 가능성이 크다.

  • 호이스팅으로 변수를 선언하기 이전에 참조가 가능하다.

var의 이런 특징은 사용이 편리하다는 장점이 있지만 유효 범위가 넓어 어디에서 어떻게 사용되는지 파악하기가 힘들어 코드의 복잡성을 증가시키기 때문에 이 문제를 보완하기 위해서 ES6부터 let과 const키워드가 추가되었다.


let

블록 레벨 스코프를 따르는 변수를 선언하기 위한 키워드이다.

// 전역 변수
let x = 10;
{
  // 지역 변수
  let x = 20;
  let y = 10;
}
console.log(x);
// 10 출력
console.log(y);
// ReferenceError: bar is not defined

var키워드는 동일한 이름을 갖는 변수를 중복해서 선언할 수 있지만 let키워드는 동일한 이름을 갖는 변수를 중복해서 선언할 수 없다.

var x = 10;
// 중복 선언 허용
var x = 20;

let y = 10;
// 중복 선언 금지
let y = 20;
// Uncaught SyntaxError: Identifier 'bar' has already been declared

호이스팅으로 선언과 초기화가 한 번에 이루어지는 var와 달리 let은 선언과 초기화가 분리되어 진행되기 때문에 참조 에러가 발생한다.

console.log(x);
// undefined로 초기화되어 출력
var x = 10;

console.log(y);
// Uncaught ReferenceError: y is not defined
let y = 10;

let은 참조부터 선언 지점까지 변수를 위한 메모리 공간이 확보되지 않게 되는데 이 구간을 일시적 사각지대(TDZ, temporal dead zone)라고 부른다.

// 전역 변수
let x = 1;

{
  console.log(x);
  // ReferenceError: x is not defined
  let x = 2;
}

블록 내에서 console.log()는 지역변수의 영향을 받아서 일시적 사각지대에 빠져서 값을 출력하지 못하게 된다.


const

상수, 변하지 않는 값을 위해 사용한다. let과 대부분 동일한 특징을 가지며 몇 가지 차이가 있다.

선언
const는 반드시 선언과 동시에 할당이 이루어져야 하며 let이나 var와 달리 재할당이 금지된다.

const x;
// SyntaxError: Missing initializer in const declaration

const y = 10;
y = 20;
// TypeError: Assignment to constant variable.

객체 타입을 const로 선언하게 되면 변수명은 보호되지만 객체의 프로퍼티는 보호되지 않는다. 객체의 내용이 변경되더라도 객체 타입 변수에 할당된 주소값은 변경되지 않기 때문에 객체 타입 변수 선언에는 const를 사용하는것이 좋다.