상당히 이해하기 어려웠다. 봐도 뭔 말인지 이해가 가지 않았다.
참고했던 자료들을 바탕으로 클로저에 대한 정의를 해보려 한다.
(외부)함수 내에 (내부)함수가 리턴값
으로 주어져 있고
이때 외부함수의 생명주기가 끝났음에도 외부함수가 가지는 지역변수를 참조하면서
외부 함수보다 오래 생존하는 내부함수를 클로저
라고 말한다.
const globalVar = '전역 변수';
function outerFn() {
const outerFnVar = 'outer 함수 내의 변수';
const innerFn = function () {
return (
'innerFn은 ' + outerFnVar + '와 ' + globalVar + '에 접근할 수 있습니다.'
);
};
return innerFn;
}
const innerFnOnGlobal = outerFn();
const message = innerFnOnGlobal();
console.log(message); // ?
함수 outerFn()
함수의 리턴 값
으로 함수 innerFn()
가 주어진걸 보고
" 클로저 함수 아니야?"
라고 의심하면 된다!
여기서
const innerFnOnGlobal = outerFn();
을 보게 되면
innerFnOnGlobal
에outerFn();
를 할당해주었으니
innerFnOnGlobal
는outerFn();
의 리턴 값인
innerFn(); 함수의 주솟 값
을 가지게 된다.!
즉,innerFnOnGlobal
=innerFn();주솟 값
이후 소명을 다한 outerFn();
는 생명을 잃게 되어 실행 컨텍스트
에서 pop()
명령어로 삭제가 되는데
그런데도 innerFn();
함수가 소멸한 outerFn();
의 지역 변수
를 참조 할 수 있는건
outerFn();
가 자신의 코드를 다 실행하고 실행 컨텍스트
에서 소멸할때 outerFn();
의 렉시컬 환경까지 소멸하는 것은 아니기 때문에
하위 스코프였던 innerFn();
에서 이미 소멸한 외부 함수인
outerFn();
의 지역 변수를 참조 할 수 있게 되는 것이다.
함수를 호출하거나 코드블록을 실행하게 되면
코드블록 실행,함수 호출
---> 실행 컨텍스트 생성
---> 실행할 함수나 코드블록을 실행 컨텍스트 스택
에 push
함---> 렉시컬 환경 생성
실행 컨텍스트란?
실행 코드에 제공할 정보들을 모아 놓은 객체
자바스크립트 코드를 실행 시 자바스크립트 엔진의 스택에 코드들이 쌓이게 됨.
함수를 호출하게 되면 실행 컨텍스트가 실행되고 함수나 코드블록들이
위에 보이는 사진과 같이 차곡차곡 쌓이게 되고 실행이 끝난 함수나 코드 블록들은 pop
메소드에 의해 없어지게 된다.
렉시컬 환경이란?
실행 컨텍스트 내부에 존재하며 식별자와 , 식별자에 바인딩된 값, 상위 스코프에 대한 참조를 기록하는 저장공간이다.
실행 컨텍스트 스택이
코드의 실행 순서를 관리하는 거라면
렉시컬 환경
은 스코프와 식별자를 관리한다.
렉시컬 환경은 스코프를 구분하여 식별자를 등록하고 관리하는 저장소 역할을함
객체의 형태로 식별자를 키
로 바인딩된 값을 값으로
구분해서 관리함.
이해를 돕기위한 사진
출처 (아주 도움이 많이 되었던 자료이다!)
위 사진과 같이실행 컨텍스트
와렉시컬 환경이
구조되어 있다.
function createFoodRecipe (foodName) {
const getFoodRecipe = function (ingredient1, ingredient2) {
return `${ingredient1} + ${ingredient2} = ${foodName}!`;
}
return getFoodRecipe;
}
const highballRecipe = createFoodRecipe('하이볼');
highballRecipe('콜라', '위스키'); // '콜라 + 위스키 = 하이볼!'
highballRecipe('탄산수', '위스키'); // '탄산수 + 위스키 = 하이볼!'
highballRecipe('토닉워터', '연태고량주'); // '토닉워터 + 연태고량주 = 하이볼!'
마지막 줄에 highballRecipe
= createFoodRecipe('하이볼');
에서
createFoodRecipe('하이볼')
으로 전달된 문자열 '하이볼'
은
highballRecipe()
함수 호출 시 계속 재사용 할 수 있다.
createFoodRecipe
가 문자열 ‘하이볼’
을 “보존”
하고 있기 때문
추가로
createFoodRecipe
함수는getFoodRecipe
함수를 리턴하고 있기 때문에getFoodRecipe(매개변수)
의 매개변수를
highballRecipe(매개변수)
에서 사용할 수 있는 것!
highballRecipe(매개변수) = getFoodRecipe(매개변수)
여러 전달인자를 가진 함수를 함수를 연속적으로 리턴하는 함수로 변경하는 행위
function makePancake(powder) {
return function (sugar) {
return function (pan) {
return `팬케이크 완성! 재료: ${powder}, ${sugar} 조리도구: ${pan}`;
}
}
}
const addSugar = makePancake('팬케이크가루');
const cookPancake = addSugar('백설탕');
const morningPancake = cookPancake('후라이팬');
// 잠깐 낮잠 자고 일어나서 ...
const lunchPancake = cookPancake('후라이팬');
위 코드와 같이 함수에 함수를 연속적으로 리턴하여 사용하는 것이
커링
언뜻 봐서는 일반 함수와 커링 함수의 차이가 느껴지지 않지만
커링
은 함수의 일부만 호출하거나, 일부 프로세스가 완료된 상태를 저장하기에 용이
클로저는 특정 데이터를 다른 코드의 실행으로부터 보호해야 할 때 용이