2023. 1. 15. 03:32ㆍJavaScript/Modern Javascript
목차 |
1. 중첩함수(nested function) |
2. 렉시컬 환경(Lexical Environment) |
3. 결과 |
4. 클로저(closure) |
1. 중첩함수(nested function)
함수 내부에서 선언한 함수는 "중첩 함수"라고 한다.
https://char1ey.tistory.com/69
Javascript 함수(선언식, 표현식, 화살표 함수)
목차 1. 함수 2. 함수 선언식 3. 함수 표현식 4. 화살표 함수 5. 콜백 함수 6. 함수의 기능 6.1. 일반 함수 6.2. 생성자 함수 6.3. 객체 메서드 1. 함수(function) 스크립트에 코드를 작성하여도 동작은 가능
char1ey.tistory.com
위의 포스팅에서 지역변수, 전역변수, 외부변수에 대해서 설명한 적이 있다.
이 두 개념을 이용해 카운터(counter)를 만들어 보자.
function makeCounter() {
let count = 0;
return function() {
return count++;
};
}
let counter = makeCounter();
console.log( counter() ); // 0
console.log( counter() ); // 1
console.log( counter() ); // 2
함수도 값이라는 이해와 return을 정확히 안다는 가정하에 어렵지 않게 받아들일 수 있을 것이다.
그래도 혹시나 이해가 안될수도 있으니 짚고 넘어가보자.
counter를 세번 반복했으므로 3이 되지만, console에서는 2가 되었다. 이는 count++을 하여 실행 후 증가이기 때문이니
이를 이해못했다면, 연산자 파트를 다시 한번 보도록 하자. ( count++은 기존값 반환 후에 증가된다. )
만약, makeCounter( )를 counter 뿐만 아니라, counter 1, coutner 2 등 다른 변수에 담아 실행하여도
변수 count에 영향을 줄 수 있을까?
이를 이해하기 위해서 렉시컬 환경을 한 번 학습해보도록하자.
2. 렉시컬 환경(Lexical Environment)
렉시컬 환경이란,
자바스크립트에서 실행중인 함수, 코드 블럭{ }, 스크립트 전체(전역)는 렉시컬 환경이라고 불리는
내부 숨김 연관 객체(internal hidden associated object)를 갖는다. - 렉시컬 환경 객체
( 말이 어렵다면, 그냥 렉시컬 환경을 갖는다고 하자.)
렉시컬 환경 객체는 환경 레코드와 외부 렉시컬 환경 참조, 두 부분으로 구성되어 있다.
환경 레코드(Environment Record)
모든 지역 변수를 프로퍼티로 저장하고 있는 객체이다.
this값과 같은 것들도 여기에 저장되어 있다.
우리가 선언하는 변수는 특수 내부 객체인 환경 레코드의 프로퍼티이다.
변수를 가져오거나 변경하는 것은 환경 레코드 프로퍼티를 가져오거나 변경하는 것이다.
전역에 선언했다면, 전역 렉시컬 환경(global Lexical Environment)이라고 한다.
렉시컬 환경에 대해 조금 더 깊이 알아보자.
렉시컬 환경(변수)
- 자바스크립트가 실행되면, 선언한 변수 전체가 각각의 렉시컬 환경에 올라간다.
- 이 때, 변수는 특수 내부 상태인 <uninitialized>가 된다.
- 코드를 실행하면서, let을 만나야 값을 참조할 수 있다. let을 만나기 전에는 변수를 사용할 수 없다.
- let을 만나 count를 선언했지만, 값을 할당하지않아 undefined가 되었다.
- count = 1에서 값이 할당되었다.
- count = 2로 값이 재할당(변경)되었다.
렉시컬 환경(함수 선언문)
함수 중에 function으로 선언한 함수 선언문은 실행과 동시에 전역 렉시컬 환경으로 끌어올려진다.
이러한 이유로 선언전에 함수를 사용할 수 있는 것이다.
(이는 호이스팅과 관련되어 있다.)
내부, 외부 렉시컬 환경
함수를 호출하여 실행하면, 새로운 렉시컬 환경이 자동으로 만들어진다.
이 렉시컬 환경에는 함수 호출 시 넘겨받은 매개변수와 함수의 지역 변수가 저장된다.
함수를 호출하여 실행시킬 때, 렉시컬 환경(내부 렉시컬 환경)이 생성되고,
내부 렉시컬 환경은 외부 렉시컬 환경(코드 블록 바깥)을 바라보게 된다.
내부 외부의 이해가 힘들다면, 코드 블럭 { } 안쪽은 내부 코드 블럭 { } 바깥쪽은 외부라고 생각해도 좋다.
함수 내부에서 해당 변수를 찾지못해 외부 렉시컬 환경에 있는 count를 찾아가게 된다.
만약 외부에서도 찾지 못하면, 외부의 외부로 나가서 찾는 방식으로 확장하여 최종적으로 전역 렉시컬로 확장한다.
3. 결과
처음에 의문을 가졌던 문제를 다시 한번 보도록 하자.
만약, makeCounter( )를 counter 뿐만 아니라, counter 1, coutner 2 등 다른 변수에 담아 실행하여도
변수 count에 영향을 줄 수 있을까?
렉시컬 환경을 공부하고 왔으니, 다음의 코드를 예상해보자.
function makeCounter() {
let count = 0
return function (){
return count++
}
}
let counter = makeCounter()
let counter1 = makeCounter()
let counter2 = makeCounter()
console.log(counter()) // 0
console.log(counter1()) // 0
console.log(counter2()) // 0
의문에 대한 답은 "변수 count에 영향을 주지 못한다." 이다.
이유를 한 번 살펴보자.
makeCounter를 호출하여 각각의 내부 렉시컬 환경이 생성되었다.
이 내부 렉시컬은 외부 렉시컬 환경을 바라본다.
makeCounter 기준으로 내부 렉시컬 환경이 생성된 그림이다.
각각의 counter, counter1, counter2 입장에서는 외부 렉시컬 환경이 된다.
각각 바라보는 렉시컬 환경이 달라서, count가 중첩되지 않는 것이다.
4. 클로저(closure)
클로저는 외부 변수를 기억하고, 외부 변수에 접근할 수 있는 함수를 의미한다.
자바스크립트에서는 자연스럽게 외부 렉시컬 환경을 찾아가면서 실행 시키기에 당연한 것이지만,
다른 언어들에서는 불가능하거나, 특수한 방법으로 함수를 만들어야 가능하다.
(위에서 본, 모든 예시는 다 클로저 개념이 들어가있다)
참고자료
https://ko.javascript.info/closure
'JavaScript > Modern Javascript' 카테고리의 다른 글
Javascript try_catch 문 (0) | 2023.01.22 |
---|---|
Javascript 객체 만들기 (0) | 2023.01.17 |
Javascript 내장 객체 Date (0) | 2023.01.15 |
Javascript 구조 분해 할당 (0) | 2023.01.15 |
Javascript 객체의 순회(Object.keys, values, entries) (0) | 2023.01.14 |