(JS에 대해 공부하면서 모던 자바스크립트 Deep Dive + mdn을 읽고 정리 요약한 내용입니다.)
본문 예시 출처 : 클로저 - JavaScript | MDN
우선 클로저는 자바스크립트 고유의 개념이 아니다. 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어(하스켈Haskell, 리스프Lisp, 얼랭Erlang, 스칼라Scala 등)에서 사용되는 중요한 특성이다.
자바스크립트 엔진은,
함수를 어디서 호출했는지 X
함수를 어디에 정의했는지 O
에 따라 상위 스코프를 결정한다.
함수가 정의된 위치와 호출되는 위치는 다를 수 있다. 렉시컬 스코프가 가능하려면 함수가 자신이 정의된 위치, 즉 상위 스코프를 기억해야 한다. 함수는 자신의 내부 슬롯[[Environment]]에 자신이 정의된 환경, 상위 스코프의 참조를 저장한다.
이때 자신의 내부 슬롯[[Environment]]에 저장된 상위 스코프의 참조는 현재 실행 중인 실행 컨텍스트의 렉시컬 환경을 가리킨다.
함수 객체는 자신이 존재하는 한 내부 슬롯[[Environment]]에 저장한 상위 스코프를 기억한다.
외부 함수보다 중첩 함수가 더 오래 유지되는 경우, 중첩 함수는 이미 생명 주기가 종료된 외부 함수의 변수를 참조 할 수 있다. 이때 중첩 함수를 클로저closure라고 부른다.
function init() {
var name = "Mozilla"; // name은 init에 의해 생성된 지역 변수이다.
function displayName() { // displayName() 은 내부 함수이며, 클로저다.
alert(name); // 부모 함수에서 선언된 변수를 사용한다.
}
displayName();
}
init();
function makeAdder(x) {
var y = 1;
return function(z) {
y = 100;
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
//클로저에 x와 y의 환경이 저장됨
console.log(add5(2)); // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
//함수 실행 시 클로저에 저장된 x, y값에 접근하여 값을 계산
클로저는 상태를 안전하게 변경하고 유지하기 위해 사용한다. 다시 말해, 상태가 의도치 않게 변경되지 않도록 상태를 안전하게 은닉information hiding하고 특정 함수에게만 상태 변경을 허용하기 위해 사용한다.
var makeCounter = function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
};
var counter1 = makeCounter();
var counter2 = makeCounter();
alert(counter1.value()); /* 0 */
counter1.increment();
counter1.increment();
alert(counter1.value()); /* 2 */
counter1.decrement();
alert(counter1.value()); /* 1 */
alert(counter2.value()); /* 0 */
❓ 캡슐화
객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것
캡슐화는 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데 이를 정보 은닉이라 한다.
정보 은닉을 함으로써 외부로부터의 적절치 못한 접근을 막아 객체의 상태가 변경되는 것을 방지하고, 객체 간의 상호 의존성(결합도coupling)을 낮출 수 있다.