스코프를 알기 위해서는 호이스팅을 알아야한다.
또한 호이스팅을 알기 전 실행컨텍스트의 개념을 알고, 실행컨텍스트 객체 안에 담긴 environmentRecord를 알아야한다. 실행컨텍스트
[JavaScript] 실행 컨텍스트
코어 자바스크립트 2강 - 실행컨텍스트 실행 컨텍스트 실행할 코드에 제공할 환경 정보들을 모아놓은 객체 스코프와 클로저 라는 개념을 이해하기 전에 살펴보자. 우리가 다음과 같은 JS파일을
junly21.tistory.com
호이스팅
environmentRecord에는 현재 컨텍스트에 관한 정보들이 저장된다. 이 때 컨텍스트 내부에 함수 선언문이 있다면 '함수 그 자체'를 수집하고, var로 선언된 변수도 수집하고 한다.
이렇게 변수 정보 수집을 마쳐도 실행 컨텍스트가 관여할 코드들은 실행되기 전의 상태이다. 코드가 실행되기 전에 우리는 그 내부의 변수명, 선언된 함수 자체 등을 알고 있게 되는것이다. 그래서 끌어올림의 개념인 호이스팅 이라는 개념이 등장했다.
아래의 코드 동작 결과를 예상해보자
function a (x) {
console.log(x); //(1)
var x;
console.log(x); //(2)
var x = 2;
console.log(x); //(3)
}
a(1)
뭔가 1, undefined, 2 순으로 출력이 될 것 같이 생겼다.
그러나 호이스팅을 고려해 동작을 예상해보면
function a () {
var x; //a의 파라미터도 여기서 선언
var x;
var x;
console.log(x); //(1)
console.log(x); //(2)
x = 2;
console.log(x); //(3)
}
a(1)
이렇게 선언이 위로 올라가서 1 1 2가 출력되게된다.
그럼 아래 코드는 어떻게 될까?
function a() {
console.log(b);
var b = "bbb";
console.log(b);
function b() {}
console.log(b);
}
a();
위의 예제를 참고하면 undefined, bbb, function b()가 출력될 것 같은데...
하지만 맨 위의 설명을 보면 선언된 함수(위 코드에서는 function b() )는 그 자체를 가져온다고 했다.
그렇기 때문에 동작 흐름은 아래와 같다.
function a() {
var b;
function b() {}
console.log(b);
b = "bbb";
console.log(b);
console.log(b);
}
a();
따라서 결과는 function b(), bbb, bbb순으로 출력된다.
참고
함수를 정의하는 세 가지 방식
function a(){ //함수 선언문. a가 함수명
}
var b = function(){ //b에 익명 함수를 할당하였음. 익명함수 표현식.
}
var c = function d(){ //c에 d라는 함수를 할당. 기명 함수 표현식.
}
함수 선언문은 함수 전체를 호이스팅해서 끌어올리는게 된다.
그러나 함수 표현식은(기명, 익명 둘 다) 선언만 올라가고 함수를 변수에 할당하는 부분은 아래 냅둔다. 즉 함수 자체가 호이스팅이 되지는 않는다.
이 차이는 혼란의 원인이 되기는 한다만 에러의 발생 원인이 될 수도 있으니 알고 있도록 하자.
스코프
스코프란? - 식별자의 유효범위.
스코프 체인
우리가 실행 컨텍스트 글에서 배웠던outerEnvironmentReference는 현재 호출된 함수가 '선언될 당시'의 LexicalEnvironment를 참조한다. 기억이 안나면 보고오자.
A함수 안에 B함수, B함수 안에 C함수가 있다고 할 때,
1.C의 outerEnvironmentReference는 B의 LexicalEnvironment를 참조한다.
2.B의 outerEnvironmentReference는 A의 LexicalEnvironment를 참조한다.
2.A의 outerEnvironmentReference는 전역컨텍스트의 LexicalEnvironment를 참조한다.
위의 원리에 의해
var a = 1;
function outer() {
var inner = function () {
console.log(a); //첫번째로 1이 찍힌다
};
inner();
console.log(a);
}
outer();
console.log(a);
이 코드를 실행할 시 outer함수를 실행하고, outer함수 내부의 inner함수를 실행하고, inner 내부의 console.log(a)를 찍어도 계속 outerEnvironmentReference를 참조해 1이 나오게 된다. 이를 스코프체인이라고 부른다.
그러나
var a = 1;
function outer() {
var inner = function () {
console.log(a); //첫번째로 1이 찍혔었는데...
var a; //여기가 추가되면??
};
inner();
console.log(a);
}
outer();
console.log(a);
이 코드는 inner 함수의 LexicalEnvironment에 a가 '값이 할당되지 않은 채로' 선언 되어있으므로
undefined, 1, 1이 출력되게 된다!!
'JS' 카테고리의 다른 글
[JS] 제너레이터 실습 - 모던자바스크립트 DeepDive (0) | 2023.10.12 |
---|---|
[JS] 프로미스 - 모던자바스크립트 DeepDive (1) | 2023.10.08 |
[JS] DOM이벤트로 익히는 호이스팅과 즉시실행함수 (1) | 2023.10.03 |
[JavaScript] 실용적으로 공부하는 클로저(Closure) (0) | 2023.09.21 |
[JavaScript] 실행 컨텍스트 (0) | 2023.09.10 |