개발/Javascript

[You don't know JS] Part2 - 4장. 호이스팅

lanace 2020. 9. 6. 06:37

호이스팅

선언문이 스코프의 어디에 있는지에 따라 스코프에 변수가 추가되는 과정의 차이가 있다.

4.1 닭이 먼저냐 달걀이 먼저냐


Javascript 코드가 위에서부터 한줄한줄 실행되지 않는다.

코드 예제 1

a = 2;
var a;

console.log(a);  // 2

원본 코드

var a;
a = 2;

console.log(a);  // 2

컴파일 결과

코드 예제 2

console.log(a);  // undefined

var a = 2;

원본 코드

var a;
console.log(a);
a = 2;

컴파일 결과

위 두가지 예제를 이해 했는가?

4.2 컴파일러는 두번 공격한다.


컴파일 과정에서 선언문을 찾아 적절한 스코프와 연결한다.

렉시컬 스코프의 핵심이다.

var a = 2;는 사실 아래 두개로 나뉜다.

  • var a
  • a = 2;

var a는 컴파일 단계에서 처리되고

a = 2; 는 실행 단계에서 처리된다.

따라서 var a 와 같이 선언문이 위로 끌어 올려졌다고 얘기하는 것이다.

이를 호이스팅 이라고 한다.

선언문만 끌어 올려지고, 다른 것들은 그대로 남아있게 된다.

함수 예제 1

foo();

function foo() {
    console.log(a);  // undefined
    var a = 2;
}

foo 함수는 아래에 선언되어 있지만 호출 할 수 있다.

근데 저렇게 되면 foo의 내용은 아래 그대로 남아있어서 undefined 가 되어야 되지 않은가?

호이스팅은 스코프별로 다르게 동작한다.


foo();  // TypeError
bar();  // ReferenceError

var foo = function bar() {
    // ...
}

원본 코드

var foo;

foo();
bar();

foo = function() {
    var bar = ...self...
}

컴파일 코드

4.3 함수가 먼저다


함수와 변수 모두 호이스팅이 된다.

그러나 함수가 더 먼저 끌어올려진다.

foo();  // 1
var foo;

function foo() {
    console.log(1);
}

foo = function {
    console.log(2);
}

원본 코드

function foo() {
    console.log(1);
}

foo();  // 1

foo = function() {
    console.log(2);
}

컴파일 코드

var foo가 중복 선언문이라 그중에 함수 선언문이 먼저 끌어 올려진것을 볼 수 있다.

foo();  // 3

function foo() {
    console.log(1);
}

var foo = function() {
    console.log(2);
}

function foo() {
    console.log(3);
}

위의 코드에선 함수로 선언된 foo가 중복되므로 가장 아래 있는 foo로 덮어 씌워진다.

foo();  // "b"

var a = true;

if (a) {
    function foo() {
        console.log("a");
    }
} else {
    function foo() {
        console.log("b");
    }
}

근데 이거 동작 안하는뎅...?? 뭐지;;

4.4 정리하기


  • var a = 2; 는 하나의 구문이 아니라 var a와 a = 2 라는 구문이 합쳐진 것이다.

  • 컴파일 단계에서 var a를 처리하고, 런타임에 a = 2가 실행된다.

  • 선언문은 어디서 나타나든 실행 전에 먼저 처리되는 호이스팅이 된다.

  • 선언문 자체는 옮겨지지만 함수 표현식의 대입문은 올라가지 않는다.

  • 중복선언을 조심하자