Skip to content

Latest commit

 

History

History
188 lines (114 loc) · 5.14 KB

File metadata and controls

188 lines (114 loc) · 5.14 KB

Hoisting

이전 글 보러가기 -> Function Scope VS Block Scope

선언문이 먼저인가? 대입문이 먼저인가?

지난번에 스코프란 변수가 어디에 저장되고 어떻게 찾는지에 대한 규칙이라고 정의했었다.

이제 우리는 스코프 내에서 일어나는 일들을 살펴볼 것이다.

선언문이 스코프 내에 어디에 있는지에 따라 스코프에 변수가 추가되는 과정이 조금씩 다른데 이 차이에 대해서 살펴보자.

자바스크립트는 코드가 실행될 때 코드가 한줄 한줄 위에서부터 차례대로 해석된다고 알고 있을 것이다.

대체로 맞는 이야기지만 이러한 고정 관념 때문에 가끔씩 프로그램을 잘못 해석하는 경우가 있다.

아래 코드를 보자.

a = 2;

var a;

console.log(a);

위에서부터 차례대로 실행된다면 이 코드의 결과값을 undefined가 나올 것으로 예상할 것이다.

하지만 이 코드의 실제 결과값은 2이다.

또 다른 예를 보자.

console.log(a);

var a = 2;

처음 예제해서 했던대로라면 왠지 a의 값은 2가 출력될지도 모른다고 생각하겠지만 이번코드의 결과값은 undefined이다.

컴파일러는 두 번 공격한다

자바스크립트가 인터프리팅하기 전에 컴파일 한다는 사실을 떠올려보자.

그리고 컴파일레이션 단계에서 렉싱타임(토크나이징)에 선언된 모든 식별자를 통해 스코프를 만드는 것을 렉시컬 스코프라고 했었다.

다시 아까의 코드를 살펴보자.

a = 2;

var a;

console.log(a);

우리는 이것을 var a = 2;를 하나의 구문으로 바라볼 수도 있겠지만 자바스크립트는 이것을 다음의 2개의 구문으로 바라본다.

  • var a;

  • a = 2;

첫째구문(선언문)은 컴파일레이션 단계에서 처리되고 둘째구문(대입문)은 실행단계까지 내버려둔다.

따라서 위 코드는 사실상 이렇게 실행된다.

var a;

a = 2;

console.log(a);

처음코드와 비교했을 때 선언문과 대입문의 위치만 바뀐 것이지만 선언문이 맨 꼭대기로 끌어올려지면서 a라는 변수에 2의 값을 대입하는 것이 가능해졌다.

이렇게 선언문을 선언된 위치에서 코드의 꼭대기로 끌어올려지는 현상을 호이스팅 이라고 한다.

요약 -> 즉, 선언문이 대입문보다 먼저다.

참고로 선언문만 끌어올려지고 다른 대입문 또는 로직들은 끌어올려지지 않고 제자리에 위치한다.

함수도 변수와 같이 마찬가지로 선언되면 호이스팅이 발생한다.

예제를 보자.

foo();

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

위 예제는 아래와 같이 호이스팅이 된다.

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

foo();

함수 foo의 선언문이 호이스팅되어 호출하는 것이 가능해졌다.

또한 var a 역시 호이스팅 되었다는 점이다.

한가지 더 주의해야할 점은 호이스팅이 스코프별로 작동한다는 것이다. 예제에서는 글로벌스코프에서 foo함수가 호이스팅 되었고 foo스코프 내에서 var a가 호이스팅 되었다.

다시 요약해보자면 호이스팅은 자신이 속한 스코프 내에서 선언문이 스코프 꼭대기로 끌어올려지는 동작을 말한다.

마지막으로 함수 선언문은 호이스팅이 발생하지만 함수 표현식은 호이스팅이 발생하지 않는다.

foo(); // TypeError
var(); // ReferenceError

var foo = function bar() {
  //
}

이 코드에 호이스팅을 적용하면 아래와 같이 적용된다.

var foo;

foo(); // TypeError
var(); // ReferenceError

foo = function bar() {

}

foo 변수는 값이 정해져있지 않아 undefined를 가지고 있는데 foo가 undefined값을 호출하려 하니 TypeError가 발생하게 되는 것이다.

함수가 먼저다

위에서 보다시피 변수와 함수 모두 선언문이라면 호이스팅이 발생한다.

만약 똑같은 변수명과 함수명을 가지게 된다면 호이스팅에도 우선순위가 있다.

결론부터 이야기하면 함수가 먼저 끌어올려지고 다음으로 변수가 끌어올려진다.

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);
}

결과값은 2가 아닌 1이 출력된다.

변수 foo와 함수 선언 foo가 겹쳐 사실상 변수 foo가 무시가 되었기 때문이다.

같은 스코프 내에서 동일 변수를 사용한다는 것은 이처럼 헷갈리는 결과를 도출한다.

프로그래밍을 할 때 반드시 변수와 함수명을 중복선언하는 것을 지양해야하는 이유이다.

출처: You don't know JS

다음 글 보러가기 -> Closure