
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script>
function foo() {
const x = 1;
const y = 2;
function bar() {
debugger;
console.log(x);
}
return bar;
}
const bar = foo();
// foo()함수를 변수 bar에 담았다.
bar();
</script>
</body>
</html>
중첩함수 예제코드를 보면 foo()함수 내부에 있는 bar()함수에 Outer environment reference가 담겨져서 리턴된다. foo()함수가 호출스택에 실행되면 내부에 있는 bar()함수에 담겨져 있던 Outer environment reference이 리턴되어서 x=1을 참조해 콘솔을 실행한다. 정리하면 중첩함수인 bar()함수가 외부에 있는 foo()함수를 상위스코프로 결정한다. 그래서 상위스코프인 foo()함수를 참조해서 x=1이 출력된 것
var outer = function() {
var a = 1;
var inner = function() {
return ++a;
};
return inner;
}
var outer2 = outer();
console.log(outer2());
console.log(outer2());
// outer함수가 실행되면 실행컨텍스트가 쌓이면서 environment Record에 a=1, inner함수가 들어가진다.
// outer함수 실행이 끝나고 inner함수가 반환되면서 outer2변수에 담겨진다. inner함수가 외부에서참조하고
// 있는 상위스코프는 outer함수이다.
// 이때 a=1은 inner함수의 Outer environment reference에 의해 살아있는 상태
// outer2함수가 또 실행되면 참조가 살아있는 변수 a=1이 참조카운터에 의해 2가되고 마지막에는 3이된다
// 전역컨텍스트가 다 종료되기전 변수a=3이 끝까지 살아남는다.
클로저는 중첩함수가 상위 스코프의 식별자를 참조하고 있고 중첩함수가 외부 함수보다 더 오래 유지되는 경우에 한정하는 것이 일반적이다.(모던 자바스크립트 Deep Dive 400쪽)
var x= 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
// 전역변수 var x=1;
// 렉시컬 환경에는 전역변수 var x=1;, foo()함수객체, bar()함수객체로 구성되어 있다.
// bar()함수객체안에 있는 렉시컬환경에서 상위 스코프인 변수인 x=1을 Outer Lexical Environment(외부 렉시컬
// 환경)으로 참조하고 있다.
// bar()함수가 foo()함수안에 있다 스코프체인이 발생
foo(); // 1
bar(); // 1
렉시컬 스코프란 함수를 어디서 호출했는지가 아니라 함수를 어디서 정의했는지에 따라 상위스코프를 경정한다. 그리고 함수 객체는 자신이 정의된 스코프, 즉 상위 스코프를 기억하면서 스코프체인이 발생한다. 이때 상위 스코프는 함수 정의가 실행될 때 정적으로 결정된다. 예제 코드를 보면 동적으로 실행할때는 foo()함수 bar()함수의 실행결과가 10이 나오지만 정적으로 실행되서 1이 나온다.
참고자료: 모던자바스크립트 Deep Dive
참고자료: 코어자바스크립트 정재남 인프런 강의