변수와 호이스팅

MyeonghoonNam·2021년 7월 26일
1

변수의 선언

JavaScript에는 세가지 변수 선언 방법이 있다. 간단하게 요약하면 다음과 같다.

  • var : function-scoped, globally-scoped 변수를 선언하고 초깃값을 설정할 수 있다.
  • let : block-scoped 변수를 선언하고 초깃값을 설정할 수 있다.
  • const : block-scoped 상수를 선언하고 초깃값을 반드시 설정해야 한다. 상수의 값을 재할당하거나 다시 선언할 수 없다.

변수 스코프

스코프란 현재 접근할 수 있는 변수들의 범위를 의미한다.

  • globally-scoped variable(전역변수): 전역에 선언된 변수는 어느 곳에서든지 해당 변수에 접근할 수 있다.
  • function-scoped variable(지역변수): 함수 내에서 선언된 변수는 해당 함수 내에서만 사용할 수 있다.
  • block-scoped local variable: 블록 내에서 선언된 변수는 해당 블록과 하위 블록 내에서만 사용할 수 있다. 블록의 범위는 중괄호 쌍 {} 으로 구분된다.

var

  • var문function-scoped(지역) 및 globally-scoped(전역) 변수를 선언하고 초깃값을 설정하는 데에 사용할 수 있다.
var a = 1;
if (a) {
  var b = 2;
}

function func() {
  var c = 3;
}

console.log(a); // 1
console.log(b); // 2 : globally-scoped
console.log(c); // c is not defined

let

  • let문mutable block-scoped 변수를 선언한다.
  • var문으로 선언된 변수함수 이외의 블록을 무시한다는 점에서 let과 다르다.
function varTest() {
  var x = 1;
  if (true) {
    var x = 2; // 상위 블록과 같은 변수
    console.log(x); // 2
  }
  console.log(x); // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2; // 상위 블록과 다른 변수
    console.log(x); // 2
  }
  console.log(x); // 1
}
  • 프로그램이나 함수의 최상위에서는 let과 var가 서로 다르게 동작한다. let은 var와 달리 전역 객체의 속성 값을 생성하지 않는다.
var x = 'global';
let y = 'global';
console.log(this.x); // "global" 전역 객체의 속성 x를 생성
console.log(this.y); // undefined 전역 객체의 속성 y를 생성하지 않음

const

  • const문은 immutable block-scoped 상수를 선언한다. 이때 초깃값을 반드시 설정해야 한다.
  • 상수의 값재할당하거나 다시 선언할 수 없다.

호이스팅

  • JavaScript의 변수, 함수, 클래스 선언이 스코프 상단으로 끌어올려지는 동작을 말한다.
  • JavaScript 엔진은 코드를 실행하면 실행하기 직전 컴파일 단계(Just-In-Time Compilation)에서 함수와 변수 선언을 스캔하며 변수, 함수, 클래스 선언들을 Lexical Environment에 추가한다.

    Lexical Environment ?

    식별자-변수값 쌍을 가지고 있는 자료구조이다.
    식별자는 변수 또는 함수의 이름이다.
    변수 값은 변수가 담고 있는 원시 값이나 오브젝트 참조(주소)를 뜻한다.
    즉, 프로그램이 실행되는 동안 변수, 함수가 존재하는 공간을 의미한다.

  • Lexical Environment의 개념적 구성은 다음과 같다.
LexicalEnvironment = {
  Identifier: <value>,
  Identifier: <function object>
}

변수 호이스팅

var 호이스팅

console.log(a); // undefined
var a = 3;
  • 위 코드를 실행하면 3이 아니라 undefined가 출력된다. 이는 JavaScript 엔진이 var로 선언된 변수를 찾아 선언을 lexical environment에 넣으면서 값을 undefined로 초기화하기 때문이다. 그 후 변수가 선언된 위치에서 값을 할당한다면 그때 undefined가 다른 값으로 대체된다.

  • 위 예제에서 변수 a에 3이 할당되기 전까지의 lexical environment를 나타내면 다음과 같다.

LexicalEnvironment = {
  a: undefined,
};

let, const 호이스팅

console.log(a); //ReferenceError: a is not defined
let a = 3;
  • 위 코드를 실행하면 ReferenceError가 발생한다. 이는 JavaScript가 let, const로 선언된 변수를 선언만 끌어올리고 값을 초기화하지 않기 때문이다. JavaScript 엔진은 var로 선언된 변수와 달리 let, const로 선언된 변수를 찾아 lexical environment에 넣으면서 값을 초기화하지 않는다. 따라서 변수 선언 위치보다 앞에서 해당 변수를 참조하면 ReferenceError 결과를 얻게 된다.

  • 블록 내에서 변수 선언이 처리되기 전까지를 tdz(temporal dead zone)상태 라고 부른다.

  • let 변수가 선언된 위치에서도 변수에 할당한 값을 찾을 수 없을 때에는 undefined를 할당한다.

  • const 변수의 경우 선언과 초깃값 설정이 동시에 이루어져야 하기 때문에 초깃값이 없다면 오류를 반환한다.

  • 위 예제에서 변수 a에 3이 할당되기 전까지의 lexical environment를 나타내면 다음과 같다.

LexicalEnvironment = {
  a: <uninitialized>
}

함수 호이스팅

함수 선언 호이스팅

  • 함수 선언코드 실행 후 컴파일 단계에서 메모리에 추가된다. 따라서 실제로 함수가 선언된 위치보다 앞에서도 함수를 실행시킬 수 있다.
helloWorld(); // 'Hello World!'
function helloWorld() {
  console.log('Hello World!');
}

함수 표현식 호이스팅

  • 함수 표현식 호이스팅함수 선언 호이스팅과 동일하게 동작하지 않는다. 아래 예시에서는 함수가 helloWorld 변수 안에 들어있기 때문에 var 변수 호이스팅과 똑같이 동작한다.
helloWorld(); // TypeError: helloWorld is not a function

var helloWorld = function () {
  console.log('Hello World!');
};

var 사용의 지양

  • var 대신 let의 사용을 지향하자.
  • JavaScript에서는 동일한 스코프 내에서 var를 이용해 같은 이름의 변수를 여러 번 선언해도 이름이 같다면 동일한 변수를 가리킨다. 이는 수많은 버그의 원인이 될 수 있다.
  • let이 블록 단위로 스코프를 지정하기 때문에 버그를 발생시킬 확률이 낮다.



참고자료

profile
꾸준히 성장하는 개발자를 목표로 합니다.

0개의 댓글