호이스팅이라는 말을 잠깐잠깐 들어만 봤지 뜻이 뭔지는 모르고 있었음.
내가 이해한 바로는 호이스팅이란 변수의 선언부와 함수의 선언부를 코드에서 위로 끌어올린다고 이해했다.
function a (x) {
console.log(x);
var x;
var x = 2;
console.log(x);
}
a(1);
예상 결과:
1
undefined
2
실제 결과:
1
1
2
기본적으로 프로그래밍 언어는 위에서부터 아래로, 왼쪽에서 오른쪽으로 코드의 순서에 따라 코드가 실행된다고 알고 있다. 그말은 즉, 만먁에 내가 sayHello()라는 함수를 실행하고 나서 그 뒤에 sayHello()라는 함수를 선언한다면 실행되지 않을 거라는 뜻이다.
/* 함수 실행 */
sayHello();
/* 함수 선언 */
function sayHello() {
console.log('hello');
}
그러니 원래같으면 이 코드는 실행될 수 없다. 왜냐하면 함수 선언이 실행보다 뒤에서 이루어졌기 때문이다.
그런데 잘 작동하는 모습을 볼 수 있다.
다시 기존 코드로 돌아가보자.
function a (x) {
console.log(x);
var x;
console.log(x);
var x = 2;
console.log(x);
}
a(1);
기존의 내 생각처럼 위에서 아래로 이 함수가 작동되는 과정을 생각해보면,
function a
가 선언되었다. (실행은 아님)console.log(x);
=> 1 출력.var x;
가 선언된다. x의 내부 초기화. 즉, var === undefined;console.log(x);
=> undefined 출력.var x = 2;
가 선언된다. x에 2 저장.그런데 오늘 들을 호이스팅 강의에 따르면, 코드가 실행될 때 변수의 선언 정보와 함수의 정보는 코드가 실행되기 전에 미리 수집된다는 것이다.
그래서 실제로는 위와 같이 노란색 영역으로 설정된 부분들이 먼저 수집된다고 볼 수 있고, 덕분에 함수가 선언되기 전에 실행해도 정상적으로 작동하는 것이다.
그리고 내가 변수 x
를 초기화했다고 생각했던 이 부분은, 실제로는 끌어올려져서 가장 먼저 선언되고 사라진 것이다.
var a = 1;
var outer = function() {
var inner = function() {
console.log(a);
var a = 3;
};
inner();
console.log(a);
}
outer();
console.log(a);
위와 같은 함수가 있을 때, var
를 이용해서 변수를 선언한 경우, var는 전역 스코프와 함수 스코프를 가지기 때문에, inner() 함수를 실행할 때 함수 내부에서 var a = 3;
의 "선언"이 끌어올려진다.(할당이 아닌 "선언"만 끌어올려진다.) 그래서 실제로는
var inner = function() {
console.log(a);
var a = 3;
};
요렇게가 아니라
var inner = function() {
var a; // 현재 undefined
console.log(a);
a = 3;
};
이런 순서로 실행된다고 봐야 한다.
그리고 전역 변수로 설정된 a
와 함수 내부에서 변수로 설정된 a
가 있을 때, 당연한 걸수도 있지만 역시 함수 내부의 a
가 참조에 있어서 더 우선순위가 높았다.
그래서 결국 inner()
의 코드가 실행되면 console.log(a)
의 결과값으로 undefined
가 출력되는 것이다.
그렇다면 let은 어떨까?
let a = 1;
let outer = function() {
let inner = function() {
console.log(a);
let a = 3;
};
inner();
console.log(a);
}
outer();
console.log(a);
내가 이해한 바에 따르면 let의 경우에도 호이스팅이 일어나지만, let은 선언
을 끌어올리는 것이 아니라 "선언이 발생했다는 사실"
을 끌어올리는 것에 가깝다고 표현해야 할 것 같다.
호이스팅이라는 것이 변수 식별자의 수집 과정을 표현한 가상 개념이라는 것을 고려하면, let
으로 선언된 변수들은 "선언" 자체
보다는 "선언이 발생했다는 사실"
이 수집되는 것이라고 말할 수 있을 것 같다.
위의 코드를 다시 보자.
let inner = function() {
console.log(a);
let a = 3;
};
여기서도 호이스팅이 일어나는데, let으로 선언된 변수는 선언 자체가 끌어올려지지는 않는다.
let inner = function() {
// 1. let a가 선언된 "사실"이 수집됨.
console.log(a);
/* 2. a가 선언된 사실은 존재하는데, a가 아직 선언되지 않았음.
=> error를 리턴.
3. 근데 만약 a가 선언된 사실도 있는데, a가 실제로 선언도 되어 있음?
그러면 그냥 출력하면 개꿀.
4. 모두가 행복하고 안전한 코딩라이프를 만끽.
*/
let a = 3;
};
그러니까 위의 inner() 함수가 실행될 때는, 변수 a가 선언된 사실은 수집되었는데 변수 a가 실제로 선언되지는 않았으므로 함수가 error를 리턴한다.
새삼 let과 const가 고마워지는 순간 ㅎㅅㅎ
도대체 2016년에 ES6 나오기 전에 당신들을 어떤 싸움을 해오셨던 건가요
무슨 정리를 이렇게 잘 하시나요????
정리하는 방법도 올려주세욤(˵ ͡° ͜ʖ ͡°˵)