스코프와 클로저는 굉장히 밀접한 관계가 있다.
아래 코드는 '스코프 체인'이라는 개념을 사용중이다.
var globalColor = 'red';
function foo() {
var fooColor = 'blue';
function bar() {
var barColor = 'yellow';
console.log(barColor); // yellow
console.log(fooColor); // blue
console.log(globalColor); // red
}
bar();
}
foo();
렉시컬 환경(Lexical Environment)은 두 부분으로 나뉜다.
1. 환경 레코드(environment Record) - 식별자 저장 하는 곳
2. 외부 렉시컬환경 참조(outer Environment Reference) -
중첩함수에서 안쪽 함수가 자신의 렉시컬 환경을 뒤져도 변수값을 찾을 수 없을 때
-> 바깥 쪽 함수의 렉시컬 환경을 참조한다. 만약 그래도 없다면?
-> 그 바깥의 렉시컬 환경을 참조한다.
이런식으로 렉시컬 환경이 null이 될때까지 쭉 참조를 이어나가는 것이 스코프체인이다.
아래 그림과 같이 체인처럼 엮어서 참조가 이루어진다.
위 2개를 더 자세히 알아보자.
A함수 내부에 B함수를 선언하고 다시 그 안에 C함수를 선언
function A(){
var a = 1;
function B() {
console.log(a);
function C() {
console.log(a);
}
}
}
(Lexcial Environment)렉시컬환경에는 2가지가 있다.
함수 C의 outerEnvironmentReference는 함수 B의 렉시컬 환경을 참조.
함수B의 렉시컬 환경에 있는 outerEnvironmentReference는 다시 함수B가 선언되던 때(A)의 렉시컬 환경을 참조.
스코프는 흔히 { }로 기준을 둘 수있다.
const a = 1;
{
const a = 2;
console.log(a); (1)
}
console.log(a); (2)
(1)줄은 스코프 내에 변수 a가 있기 때문에 그대로 2를 출력한다. 하지만
스코프 안에 변수 a가 없는 상황이라면,?
const a = 1;
{
console.log(a); // 스코프 내에 변수 a가 없기 때문에 바깥 중 가장 가까이 있는 변수를 찾을 것이다. 이것이 스코프체인이다.
}
console.log(a);
아래의 코드를 눈여겨봐라.
본인은 이 코드로 클로저와 스코프체인을 한 번에 잡을 수 있었다.
if(1 < 2) {
function f = function() {
let abc = 123;
let ddd = function() {
return abc; // 스코프체인에 의해 abc가 스코프에 없으니 상위 스코프 뒤짐.
}
return ddd;
}
}
const ccc = f();
console.log(ccc()); /// 123
첫번째 for문 내에서 arr[i]에 매핑한 값은 특정 값이 아니라 function() {return i};라는 함수입니다. 해당 함수는 지역변수를 가지고 있지 않으니 나중에 실행될때 본인 스코프를 벗어나서 상위 스코프로 올라가면서 i를 참조하려 할텐데 해당 함수가 실제 실행되는 시점인 두번째 for 문에서는 i값이 이미 첫번째 for문이 끝난시점이라 5로 되어있어서 (var로 선언했기 때문에 블록스코프 이후에도 i가 유지됩니다) 모든 결과값이 5로 통일되는겁니다.