어휘적 환경(Lexical Environment)
자바스크립트는 어휘적 환경을 갖습니다.
어휘적 환경이란 간단하게 말해 정적인(변하지않는)환경입니다.
let one;
one = 1;
function addOne(num){
console.log(one + num);
}
addOne(5);
이러한 코드가 있을 때 어떻게 동작하는지 알아봅시다.
코드가 실행되면 스크립트에서 선언한 변수들이 Lexical 환경에 올라가게 됩니다.
let과 addOne함수 둘다 환경에 올라가지만 let변수는 초기화가 되어있지 않기 때문에 사용은 못합니다.
그에 비해 함수는 변수와 달리 바로 초기화 됩니다.
다음사진을 보겠습니다
.
이제 let one을 만나게 되면 아직 할당은 되어있지 않기 때문에 초기값 undefined을 얻게 됩니다.
이제 사용을 해도 에러가 발생하지 않습니다. 값이 undefined일 뿐
이제 변수 one에 1이 할당되어졌습니다.
함수 선언은 초기에 완료되었기 때문에 마지막 라인으로 가서 함수가 실행됩니다.
그 순간 새로운 Lexical 환경이 만들어집니다. 이곳에는 함수가 넘겨받은 매개변수, 지역변수들이 저장됩니다.
함수가 호출되는 동안에는 함수에서 만들어진 내부 Lexical환경과 외부에서 받은 전역 Lexical환경 두개를 가지게 됩니다.
내부 Lexical 환경은 외부 Lexical환경에 대한 참조를 가지게 됩니다. 즉 코드에서 변수를 찾을 때 내부에서 찾고 없으면
외부, 거기에도 없다면 전역 Lexical 환경까지 범위를 넓혀서 찾습니다.
함수에서 one과 num은 내부 Lexical 환경에서 먼저 찾습니다. num은 찾았지만, one은 없습니다.
이러한 경우 외부로 넓혀서 있는지 찾고 찾게 되면 one + num을 실행할 수 있게 됩니다.
다른 예제를 보겠습니다.
Add함수를 만들어주는 함수 makeAdder은 최초 실행 시 makeAdder와 변수 add3은 전역 Lexical 환경에 들어가게 됩니다. add3은 초기화 되지않은 상태이고, 사용할 수 없습니다.
const add3 = makeAdder(3); 가 실행될 때 makeAdder가 실행되고, Lexical 환경이 만들어지게 됩니다. 이 때 전달받은 x의 값이 들어가게 됩니다. 함수의 Lexical 환경에는 넘겨받은 매개변수와 지역변수들이 저장됩니다.
전역 Lexical 환경에 있던 add3은 함수가 실행되어서 return 하는 함수가 됩니다.
이제 마지막 줄이 실행되면서 빨간 줄의 함수가 실행됩니다. 이 때 또다른 Lexical 환경이 만들어집니다.
y가 2로 들어가게 됩니다.
이제 x+y를 하게 된다면 x와 y를 찾게 됩니다. y는 있지만 x는 없으므로 외부 Lexical 환경으로 가서 찾습니다.
정리를 해보면 위의 빨간줄의 함수는 자신이 y를 가지고 있고, 상위 함수인 makeAdder의 x에 접근할 수 있습니다.
add3 함수가 생성된 이후에는 상위함수인 makeAdder의 x에 접근이 가능합니다.
이것을 클로저(Closure)라고 합니다.
클로저
- 함수와 그 함수의 렉시컬 환경의 조합
- 함수가 생성될 당시의 외부 변수를 기억
- 생성된 이후에도 계속 접근 가능
외부 함수의 실행이 끝나서 외부 함수가 소멸이 되어도 내부 함수가 외부함수에 접근할 수 있습니다.
여기서 makeAdder(10)이 호출되었지만 add3은 아무런 변화가 없습니다.
즉 add10과 add3은 서로 다른 환경을 가지고 있습니다.
마지막으로 하나의 예제를 더 보겠습니다.
function makeCounter(){
let num=0;
return function(){
return num++;
};
}
let counter = makeCounter();
console.log(counter());
console.log(counter());
console.log(counter());
conunter() 함수를 실행하면 num++을 해준다. function()안에 num이 없기때문에 해당값을 찾기 위해서
makeCounter()함수까지 범위를 넓혀 찾게 된다. 이게 바로 클로저이다
function()함수가 makeCounter()함수안에 있기 때문에 가능한 일이다.
즉 해당 블록 {} 안에서 사용기 가능하다.
정리
클로저는 내부함수의 변수가 외부함수의 변수에 접근할 수 있는 것을 의미합니다.
즉, 클로저 함수안에서는 지역변수, 외부함수의 변수, 전역변수 모두 다 접근이 가능합니다.
그래서 클로저가 필요한 이유가 뭐야?
1. 전역변수를 줄일 수 있습니다.
2. 상태유지 즉 현재 상태를 기억하고 변경된 최신 상태를 유지할 수 있습니다.
3. 정보의 은닉
'프론트엔드 > javascript' 카테고리의 다른 글
자바스크립트 - call, apply, bind (0) | 2023.04.09 |
---|---|
자바스크립트 - setTimeout/setInterval (0) | 2023.04.09 |
자바스크립트 - 나머지 매개변수, 전개구문(Rest parameters, Spread syntax) (0) | 2023.04.09 |
자바스크립트 - 구조 분해 할당(Destructuring assignment) (0) | 2023.04.08 |
자바스크립트 - 배열 메소드2(sort, reduce) (0) | 2023.04.08 |