렉시컬환경
개념
- 환경레코드와 외부렉시컬환경에 대한 참조로 구성
- 함수는 선언 전에도 전역 렉시컬 환경의 환경레코드에 초기화되므로 사용할 수 있다 (호이스팅)
- 함수는 선언 시 숨김 프로퍼티
[[Environment]]에 외부 렉시컬 환경에 대한 참조(값이 아님!)를 저장한다. - 함수가 실행될 때마다 독립적인 렉시컬환경이 생성된다
- (주의) 외부 렉시컬 환경에 대한 참조는 변하지 않는다
- 함수는 변수를 내부 환경레코드 -> 외부 렉시컬환경 순서로 찾음
예시코드
- 코드
function makeCounter() { let count = 0; return function() { return count++; } } const counter = makeCounter(); console.log(counter()); //0 console.log(counter()); //1 console.log(counter()); //2- 코드의 실행흐름 별 렉시컬환경 변화
- 맨 처음
- 전역 렉시컬 환경(*) 생성
- 이 스코프에서 함수 선언문 스캔
- makeCounter는 보이지만 makeCounter의 내부 함수는 안보임!
- (*)의 환경 레코드에 프로퍼티 makeCounter 생성 및 초기화
- makeCounter 선언부
- makeCounter의 숨김 프로퍼티
[[Environment]]에 (*)에 대한 참조 저장
- makeCounter의 숨김 프로퍼티
- makeCounter 호출
- 맨 처음: makeCounter 함수의 렉시컬 환경(**) 생성
- (**)의 환경 레코드에 프로퍼티 count <> 로 생성
- (**)의 환경 레코드에 프로퍼티 익명함수 생성 및 초기화
- count 선언: count = 0 으로 초기화
- 익명함수 선언: 이 함수의 숨김 프로퍼티
[[Environment]]에 (**)에 대한 참조 저장
- 맨 처음: makeCounter 함수의 렉시컬 환경(**) 생성
- counter 호출 (1)
- counter의 렉시컬 환경(***) 환경 생성
- count가 내부에 없으므로 외부렉시컬 환경(**) 참조함
- (**)의 count 1 증가
- counter 호출 (2)
- counter의 렉시컬 환경(***) 환경 생성
- count가 내부에 없으므로 외부렉시컬 환경(**) 참조함
- (**)의 count 1 증가
- counter 호출 (3)
- counter의 렉시컬 환경(***) 환경 생성
- count가 내부에 없으므로 외부렉시컬 환경(**) 참조함
- (**)의 count 1 증가
- 맨 처음
연습문제 오답노트
- 문제
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function() { // shooter 함수
alert( i ); // 몇 번째 shooter인지 출력해줘야 함
};
shooters.push(shooter);
i++;
}
return shooters;
}
let army = makeArmy();
army[0](); // 0번째 shooter가 10을 출력함
army[5](); // 5번째 shooter 역시 10을 출력함
// 모든 shooter가 자신의 번호 대신 10을 출력하고 있음
- 오답
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let shooter = function() {
let j = i; // 이부분
alert( j );
};
shooters.push(shooter);
i++;
}
return shooters;
}
let army = makeArmy();
army[0](); // 10
army[5](); // 10
- 정답
function makeArmy() {
let shooters = [];
let i = 0;
while (i < 10) {
let j = i; // 이 부분
let shooter = function() {
alert( j );
};
shooters.push(shooter);
i++;
}
return shooters;
}
let army = makeArmy();
army[0](); // 0
army[5](); // 5
- 틀린 이유:
- 조건문, 반복문의 스코프 개념 숙지 못함
- 렉시컬 환경을 헷갈림
- 오답이 동작하지 않는이유
- 내부함수의 외부 렉시컬 환경에 변수 j를 넣으려면 내부함수가 선언될때 j 가 있어야 하는데, 내가 쓴 코드는 내부함수가 실행될 때 선언됨
출처
모던자바스크립트 https://ko.javascript.info/closure
'배운 것들 > 언어' 카테고리의 다른 글
| JavaScript 심볼이 JSON stringify 되지 않는 이유와 대응 (3) | 2025.05.03 |
|---|---|
| JVM Anatomy 세션 정리, 해석 (8) | 2024.12.27 |