상위 스코프의 식별자를 참조하고 있고, 본인의 외부 함수보다 더 오래 살아있다면 클로저! (엘라 짱)
클로저에 의해 참조된 변수는 자유변수! (엘라 짱)
function outer() {
let name = 'shinsehantan'
return function inner() {
alert(name);
}
}
let inner = outer(); // 외부함수 실행하여 inner라는 변수에 담음.
inner();
// inner 실행 - alert를 띄워야 함.
// alert에는 name이 필요.name은 outer 함수에 있음.
// outer 함수가 이미 return과 함께 생을 마감했고, 실행 컨택스트 스택에서도 제거되었지만
// outer 함수의 렉시컬 환경은 딱히 건드리지 않음.
// 그래서 inner가 태어날 때 참조하기로 결정된, name에 접근할 수 있음
// inner는 클로저! 클로저에 의해 참조된 변수 name은 자유변수!
// alert('신세한탄')은 정상적으로 동작!
어떻게 그렇게 되지? 스코프?
변수의 유효 범위인 '렉시컬 스코프'에 대한 이해가 필요
렉시컬 스코프란, 정적 스코프! 함수가 정의되는 시점에 참조에 대한 정보가 정해짐!
자바스크립트는 렉시컬 스코프이기 때문에 함수 선언 당시의 환경을 기억함.
숨김 프로퍼티인 [[Environment]]를 이용해 자신이 어디서 만들어졌는지 기억할 수 있음.
렉시컬 스코프를 사용하는 해당 함수 객체는 자신의 상위 스코프를 항상 알 수 있음!
가비지 컬렉터?
함수 호출이 끝나면 함수에 대응하는 렉시컬 환경이 메모리에서 제거됨.
자바스크립트에서 모든 객체는 도달 가능한 상태일 때만 메모리에 유지됨.
함수의 호출이 끝난 후에도 여전히 도달 가능한 중첩 함수가 존재한다면, 도달 가능한 상태인 것이고 그렇기 때문에 렉시컬 환경이 메모리에 유지됨!
but V8 엔진(크롬, 오페라)에서는 계속해서 메모리 최적화를 진행함.
외부 변수를 더이상 참조하지 못하는 경우도 생길 수 있다고 함!
function makeFunc() {
let name = "shinsehantan";
function printAlert() {
alert(name);
}
return printAlert;
}
let myFunc = makeFunc();
// myFunc라는 변수에 printAlert이 리턴되어 담김.
// makeFucn 내부의 printAlert 함수는 makeFunc의 name인 shinsehantan을 참조하고 있었음.
// makeFunc이 실행되어 끝났고, 그래서 그 내부에 선언된 변수도 생명을 잃을 것 같아 보이지만!
// 참조하는 주체가 남아있기 때문에 이 유효범위의 어휘적 환경이 유지됨.
myFunc();
// myFunc 함수 실행 = 리턴된 printAlert 함수를 실행
// 필요한 name 변수에 접근 가능!
// 결과는 alert로 shinsehantan이 잘 뜸!
✔️✔️✔️✔️ test 1 ✔️✔️✔️✔️
let result = [];
for (let i = 0; i < 5; i++) {
result.push(function () {
return i
})
}
console.log(result[1]())
// result = [0,1,2,3,4]일테니, result[1] === 1 일까? ㅇㅇ
console.log(result[3]())
// result = [0,1,2,3,4]일테니, result[3] === 3 일까? ㅇㅇ
✔️✔️✔️✔️ test 2 ✔️✔️✔️✔️
var result = [];
for (var i = 0; i < 5; i++) {
result.push(function () {
return i
})
}
console.log(result[1]())
// result[1] === 1 일까? ㄴㄴ 5임
console.log(result[3]())
// result[3] === 3 일까? ㄴㄴ 5임
// 콜백함수는 콜스택이 모두 비워진 다음에 이벤트루프에 의해 콜스택으로 푸시됨.
// for문이 모두 돌았을 때, i는 이미 4?5?인 상태
// 콜백함수는 실행되지 않은 상태로 전역변수 i를 참조하고 있는 상태
// 이때 콜백함수가 실행되면 참조하고있던 전역변수 5를 사용하게 됨.
클로저란?
어떻게 그렇게 되지? 스코프?
가비지 컬렉터?
언제 쓰나?
출처