1. 클로저란?
- 함수형 프로그래밍의 핵심이 되는 요소
- 함수가 선언된 렉시컬 환경 과의 조합을 말한다.
function outer() {
var outerVar = "외부 변수";
function inner() {
console.log(outerVar); // 외부 변수에 접근 가능
}
return inner;
}
const innerFunc = outer();
innerFunc(); // "외부 변수" 출력
2. 렉시컬 환경(Lexical Environment)
자바스크립트에서 함수가 선언되면, 그 함수의 렉시컬 환경이라는 특별한 구조가 만들어진다.
📍 렉시컬 환경은 함수가 선언될 때 어떤 변수가 어디에 있는지를 저장하고 관리 하는 일종의 '지도' 역할을 한다.
함수가 실행될 때, 이 지도에 따라 변수들이 어떻게 처리될지 결정되며, 이 환경 안에는 함수 내부에서 선언된 변수들이 기록된다.
따라서 이 구조는 해당 함수가 접근할 수 있는 모든 변수와 상수, 함수 등을 기억하고 관리하는데 따라서 스코프를 관리하는 핵심 메커니즘이다.
2-1. 스코프체인
스코프 체인은 렉시컬 환경들이 서로 연결되어 있는 구조라고 볼 수 있다.
함수가 중첩되어 있을 때, 자바스크립트는 현재 함수의 렉시컬 환경에서 변수를 찾고, 만약 찾지 못하면 상위 렉시컬 환경(= 외부렉시컬환경) 으로 계속 거슬러 올라가면서 변수를 탐색한다
=> 우리는 이것을 스코프체인이라고 부른다. 는 것을 이미 알고 있다 !
2-2. 함수객체의 내부슬롯[[Environment]]
📌 자바스크립트 엔진은 함수를 어디서 "호출"했는지가 아니라 어디에 정의했는지에 따라 상위 스코프가 결정된다.
함수가 정의된 위치와 호출되는 위치는 다를 수 있다.
따라서 함수는 자신이 호출되는 환경과는 상관없이 정의된 환경인 상위스코프를 기억하고자 한다.
이를 위해 함수는 자신의 내부슬롯[[Environment]] 에 자신이 정의되는 환경인 상위스코프의 참조를 저장하게 된다.
따라서 [[Environment]] 는 함수가 선언된 시점의 렉시컬 환경을 저장하는 슬롯, 공간 이고 이 슬롯 덕분에 자바스크립트의 함수는 자신이 정의된 스코프(렉시컬 환경)에서 변수를 참조할 수 있으며, 클로저가 가능해진다.
함수가 호출될 때마다 자바스크립트 엔진은 이 슬롯을 통해 함수가 참조할 외부 변수를 기억하고 해당 변수를 함수 내에서 사용할 수 있도록 한다. 따라서 함수는 자신이 선언된 위치에서 어떤 변수를 사용할 수 있는지 기억하기 위해 [[Environment]] 슬롯을 이용하게 된다.
📍작동원리
함수가 실행되면, 자바스크립트는 실행 컨텍스트 를 생성한다.
이때 함수 내부의 변수는 환경 레코드(Environment Record) 에 저장된다.
하지만 함수가 선언된 시점의 외부 변수는 함수 내부에 없기 때문에, 자바스크립트는 [[Environment]] 슬롯을 참조하여 외부 변수를 추적하게 된다.
즉, 함수가 호출될 때 외부 변수를 참조할 때는 [[Environment]] 내부 슬롯을 사용하여 변수를 찾게된다.
이 슬롯은 렉시컬 환경(Lexical Environment)을 기억하기 때문에, 함수가 외부에서 선언된 변수를 참조할 수 있게된다.
const x = 1;
function foo() {
const x = 10;
bar();
}
// 함수 bar는 자신의 상위 스코프, 즉 전역 렉시컬 환경을 [[Environment]]에 저장하여 기억한다.
function bar() {
console.log(x);
}
foo(); // ?
bar(); // ?
클로저는 외부 함수가 실행을 마친 후에도 그 함수 내에서 선언된 변수를 내부 함수가 계속 참조할 수 있도록 하는 메커니즘인데, 이때 [[Environment]]에 저장된 렉시컬 환경 덕분에 외부 변수가 계속 메모리에 유지된다.
3. 클로저의 활용
클로저는 상태state를 안전하게 변경하고 유지하기 위해 사용된다.
상태를 안전하게 은닉(information hiding)하고 특정 함수에게만 상태 변경을 허용하기 위해 사용한다.
💡 카운터 ( 상태유지 )
function createCounter() {
let count = 0; // 외부 함수의 변수 (상태)
return function() {
count++; // 클로저로 외부 함수의 변수인 count에 접근
console.log(`현재 카운트: ${count}`);
};
}
const counter = createCounter();
counter(); // "현재 카운트: 1"
counter(); // "현재 카운트: 2"
counter(); // "현재 카운트: 3"
💡 정보은닉
function createPerson(name) {
let _name = name; // 외부에서 접근할 수 없는 변수
return {
getName: function() {
return _name; // 클로저로 _name에 접근
},
setName: function(newName) {
_name = newName; // 클로저로 _name을 변경 가능
}
};
}
const person = createPerson("John");
console.log(person.getName()); // "John"
person.setName("Jane");
console.log(person.getName()); // "Jane"
_name 변수는 함수 내부에 선언된 지역 변수 라서 외부에서 직접 접근할 수 없고, 오직 getName과 setName 메서드를 통해서만 접근할 수 있다.
함수가 반환된 이후에도 내부 함수(getName, setName)는 자신이 선언된 렉시컬 환경(즉, 함수의 스코프)에 접근할 수 있게 되어, 외부에서는 직접 접근할 수 없는 변수를 안전하게 다룰 수 있다.
이렇게 클로저를 사용해 외부에서 직접 수정할 수 없는 프라이빗 변수를 만들 수 있음
4. 캡슐화와 정보 은닉
객체의 상태를 나타내는 프로퍼티와 프로터리를 참조하고 조작할 수 있는 메서드를 하나로 묶는 것을 캡슐화라고 한다.
캡슐화는 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이것은 정보은닉이라고 한다.
정보 은닉은 외부에서 직접 접근할 수 없는 변수를 만드는 기법이다.
구현의 일부를 외부에 공개되지 않도록 감추어 적절치 못한 접근으로부터 객체의 상태가 변경되는 것을 방지해 정보를 보호하고, 객체 간의 상호 의존성, 즉 결합도를 낮추는 효과가 있다. 즉 외부에서 변수를 직접적으로 수정하거나 읽을 수 없도록 보호할 수 있다.
정리!
자바스크립트는 함수를 선언할 때 해당 함수의 스코프 정보를 기억한다. => 렉시컬 환경
함수가 호출되면 해당 함수의 렉시컬 환경이 생성되는데, 여기에는 현재 함수 내에서 사용되는 변수들과 외부 스코프에서 선언된 변수들이 포함된다
클로저(Closure) 는 함수가 선언될 때의 렉시컬 환경(Lexical Environment)을 기억하여, 함수가 외부 함수의 변수에 접근할 수 있도록 해주는 기능이다. 클로저는 함수가 호출된 이후에도, 해당 함수가 선언된 스코프에 있는 변수들에 계속 접근할 수 있게 만들어준다.
'Deep Dive 정리' 카테고리의 다른 글
[JS Deep Dive] 27장 - 배열 (2) (0) | 2024.10.31 |
---|---|
[JS Deep Dive] 27장 - 배열 (1) (0) | 2024.10.31 |
[JS Deep Dive] 22장 - this (0) | 2024.09.19 |
[JS Deep Dive] 20장 - strict mode (1) | 2024.09.11 |
[JS Deep Dive] 19장 - 프로토타입 (0) | 2024.09.11 |