- 대강 다시 설명하자면, 실행 컨텍스트가 생성되면 js엔진은 해당 컨텍스트에서 실행에 필요한 여러가지 정보를 담은 "활성객체"라는 객체를 생성하는데, 이 활성 객체에 함수의 인자들을 유사 배열 형태로 담는 arguments라는 객체가 생성되고, 현재 컨텍스트의 유효범위를 나타내는 스코프 정보를 생성, 이후 변수생성과 this 바인딩을 한다고 하였다.
- 스코프 정보는 현재 실행중인 실행 컨텍스트 안에서 연결 리스트와 유사한 형식으로 만들어진다 하였는데, 이 리스트를 "스코프 체인"이라고 한다 하였다. [[scope]] 프로퍼티로 참조된다.
- 다시 설명하자면, 유효 범위를 나타내는 스코프가 [[scope]] 프로퍼티로 각 함수 객체 내에서 연결리스트 형식으로 관리되는데, 이 스코프간의 상하관계를 "스코프 체인"이라고 한다는 것이다.
- 그렇다면 변수의 스코프란? 이라는 질문은 무엇을 묻는 질문일까?
이는 선언된 변수가 어느 위치에서 유효한가를 묻는다고 보면 된다.
2. 전역 실행 컨텍스트의 스코프 체인
예시)
var var1 =1;
var var2 =2;
console.log(var1);
console.log(var2);
- 위 코드 실행시 먼저 전역 실행 컨텍스트로 생성이 되고, 변수 객체(활성 객체)가 만들어진다.
* (여기서 말하는 변수객체와 활성 객체는 같은 것을 의미한다.)
- 이 변수 객체(활성 객체)의 스코프 체인은 자신이 최상위에 위치하는 변수 객체(활성 객체)이기에, 자기 자신만을 가진다.
- 다시 말해, 변수 객체의 [[scope]]는 변수 객체 자신을 가리키는 것이다.
- 그 후, var1,var2 변수들이 생성되고 변수 객체에 의해 참조된다.
위 코드를 그림으로 나타낸 것이다.
- 스코프 체인을 다시 이야기하면, 자바스크립트도 다른 언어와 마찬가지로 스코프, 즉 유효범위가 있다. 이 유효범위 안에서 변수와 함수가 존재하는 것이다.
- 예를 들어 {}로 묶어있는 범위 안에서 선언된 변수는 블록이 끝나는 순간 사라지므로, 밖에서는 접근이 불가능하다. 그러나 자바스크립트에서는 "오직 함수만이" 유효범위의 한 단위가 되는 것이다.
- 따라서 스코프란 변수의 접근 가능 범위를 뜻하는 말이고, 스코프 간의 상하관계를 스코프 체인이라 부르는 것이다.
3. 스코프 체인 예시(2)
var value ="value1";
functionprintFunc(){
var value ="value2";
functionprintValue(){
return value;
}
console.log(printValue());
}
printFunc();
다음과 같은 코드가 있다고 가정하자.이럴 경우 그림으로 표현하게 된다면
이와 같은 형태로 실행된다.
4. 스코프 체인 예시 (3)
var value ="value1";
functionprintValue(){
return value;
}
functionprintFunc(Func){
var value ="value2";
console.log(func());
}
printFunc(printValue);
- 함수 객체가 처음 생성될 당시 실행 컨텍스트가 무엇인지 생각하는 것이 중요하다.
("불러올 함수가 어느 실행 컨텍스트에 위치한가?")
- 각 함수 객체가 처음 생성될 때 [[scope]]는 전역 객체의 [[scope]]를 참조한다.
- 따라서 함수 실행 시 생성되는 실행 컨텍스트의 스코프 체인은 전역 객체와 그 앞에 새롭게 만들어진 변수 객체가 추가된다.
5. 식별자 인식
- 스코프 체인으로 식별자 인식이 이루어진다.
- 식별자 인식은 스코프 체인의 첫 번째 변수 객체부터 시작한다.
(식별자와 대응되는 이름을 가진 프로퍼티가 있는가?)
- 스코프 체인의 가장 앞에 있는 객체가 변수 객체이므로, 이 객체에 있는 공식 인자, 내부함수, 지역변수에 대응되는지 먼저 확인한다.
- 첫 번째 객체에서 대응되는 프로퍼티를 발견하지 못할 경우 대음 객체로 이동하게 되는데, 이는 찾을 때 까지 계속해서 내려가게 된다.
- this 는 식별자가 아닌 "키워드"로 분류되기 때문에, 스코프 체인의 참조 없이 접근이 가능하다.
6. 클로저
예시)
functionouterFunc(){
var x =10;
varinnerFunc=function(){ console.log(x);}
return innerFunc;
}
var inner =outerFunc();
inner();//10
- 이 내용을 앞의 내용처럼 스코프 체인을 그려본다면 다음과 같다.
- innerFunc()의 [[scope]]은 outerFunc 변수 객체와 전역 객체를 가진다.
- 그런데 여기서 보면 innerFunc()은 outerFunc()이 끝난 뒤 실행된다.
- 그렇다면 outerFunc 실행 컨텍스트가 사라진 이후에 innerFunc 실행 컨텍스트가 생성되는 것이라 생각할 수 있다.
- 그러나 outerFunc 실행 컨텍스트가 사라졌더라도, outerFunc변수 객체는 여전히 남아있고, innerFunc의 스코프 체인으로 참조되고 있다.
- 이것이 자바스크립트에서 구현한 클로저라는 개념이다.
- 간단하게 이미 생명주기가 끝난 외부함수의 변수를 참조하는 것을 클로저라고 하는데, 이 때 클로저에 참조되는 외부변수를 "자유변수"라고 한다.
- closure 라는 이름은 함수가 자유변수에 닫혀있다는 의미로, "자유변수에 엮여있는 함수"라고 이해하면 된다.
댓글 영역