반응형
Lexical Scope
변수의 유효 범위를 결정하는 규칙.
코드가 실행될 때가 아니라 작성될 때 결정됨.
Lexical = 문맥
스코프 예시
let globalVar = "global"; // 글로벌 스코프
function outerFunction() {
let outerVar = "outer"; // outerFunction의 렉시컬 스코프
function innerFunction() {
let innerVar = "inner"; // innerFunction의 렉시컬 스코프
console.log(globalVar); // "global"
console.log(outerVar); // "outer"
console.log(innerVar); // "inner"
}
innerFunction();
}
outerFunction();
렉시컬 스코프 예시
var x = 1;
function bar() {
console.log(x);
}
function foo() {
var x = 10;
bar();
}
foo(); // 1 -> 함수가 선언된 위치가 전역이기 때문에
bar(); // 1
함수를 어디서 호출했는지에 따라 바뀌는걸 dynamic scope라고 하는데, 대부분의 언어는 lexical scope(=static scope)를 따른다.
- 함수 객체의 내부 슬롯
[[Environment]]
에는 상위 스코프의 참조값이 저장된다. - 전역에 선언된 함수에는 내부 슬롯
[[Environment]]
에 전역 스코프의 참조값이 저장됨. - bar 함수의 내부 슬롯
[[Environment]]
에는 전역 스코프의 참조가 저장되어 x는 1의 값을 가지고 있음.
Lexical Environment
실행 컨텍스트의 일부분으로, 변수를 저장하고 관리.
각 함수가 호출되거나 블록 진입시(=실행 컨텍스트가 생성될 때마다)
새로운 렉시컬 환경이 생성된다.
렉시컬 환경의 두 가지 주요 부분:
- Environment Record: 현재 스코프의 모든 변수와 함수 저장.
- Outer Lexical Environment Reference (외부 렉시컬 환경 참조): 상위 스코프 참조.
Execution Context
JS 코드가 실행되는 환경.
실행 컨텍스트를 생성하는 코드
- Global
- 코드가 처음 실행될 떄 생성됨.
- 전역 객체와 this 포함.
- JS 프로세스가 종료될 때까지 유지.
- Function
- 함수가 호출될 때마다 실행됨.
- 함수의 arguments, local variables, this를 포함.
- 함수 실행이 완료되면 컨텍스트 스택에서 제거됨.
- Eval
eval
함수가 실행될 때 생성됨.
- Module
- 모듈 내부에 존재하는 코드.
this = 현재 실행 컨텍스트에서 참조하는 객체
실행된 순서대로 실행 컨텍스트 스택에 쌓인다.
맨 밑바닥에는 Global EC가 프로세스 종료될 때까지 깔려있다.
First-class Object (일급 객체) (=First-class Citizen)
- 변수에 할당할 수 있다.
- 다른 함수의 인자로 전달할 수 있다.
- 다른 함수의 반환값으로 사용할 수 있다.
- 동적으로 생성할 수 있다.
- JS에서는 함수가 일급 객체이다.
- 함수가 변수에 할당될 수 있고, 다른 함수의 인자로 전달되거나 반환값으로 사용될 수 있음.
Closure
"A closure is the combination of a function and the lexical environment within which that function was declared."
클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다.
- 여기서 말하는 렉시컬 환경은 함수가 정의된 스코프
(=상위 스코프, 실행 컨텍스트의 렉시컬 환경)
- 모든 함수는 상위 스코프를 기억하므로, 어디서 호출되든 상위 스코프의 식별자
(변수, 함수, 클래스 등)
를 참조할 수 있다. (lexical scope) - 중첩 함수
(Inner 함수)
이면서 상위 스코프의 식별자를 참조하지 않거나, 참조 하더라도 Outer 함수보다 먼저 소멸되면 클로저라고 하지 않는다.
function foo() {
const x = 1;
const y = 2;
// 클로저
// 중첩 함수 bar는 외부 함수보다 더 오래 유지되며 상위 스코프의 식별자를 참조한다.
function bar() {
debugger;
console.log(x);
}
return bar;
}
const bar = foo();
bar();
Closure 활용
- 정보 은닉
소멸될 외부 함수에 변수를 선언하고 클로저 함수를 반환하게 해두면 반환된 클로저 함수로만 변수에 접근할 수있다.
예시
const inc = (function () {
let counter = 0; // 외부에서 접근할 수 없음.
// Closure
return function () {
return ++counter;
};
})();
console.log(inc()); // 1
console.log(inc()); // 2
console.log(inc()); // 3
// 함수를 반환하는 고차 함수
// 이 함수는 카운트 상태를 유지하기 위한 자유 변수 counter를 기억하는 클로저를 반환한다.
const counter = (function() {
// 카운트 상태를 유지하기 위한 자유 변수
let counter = 0;
// 함수를 인수로 전달받는 클로저를 반환
return function(aux) {
// 인수로 전달받은 보조 함수에 상태 변경을 위임한다.
counter = aux(counter);
return counter;
};
}());
// 보조 함수
function increase(n) {
return ++n;
}
// 보조 함수
function decrease(n) {
return --n;
}
// 보조 함수를 전달하여 호출
console.log(counter(increase)); // 1
console.log(counter(increase)); // 2
// 자유 변수를 공유한다.
console.log(counter(decrease)); // 1
console.log(counter(decrease)); // 0
- 외부에서 접근 불가능한 변수의 값을 변경할 함수를 넣어줄 수 있다.
반응형