피드백 및 오류 수정은 항상 환영합니다. 꼭 이상하거나 잘못되어져 있는 내용들에 대해서는 딴지를 걸어주세요!🐶
클로저는 자바스크립트의 고유한 개념이 아니라 함수형 프로그래밍 언어에서 전부 사용되는 특성이다.
클로저의 정의는 다음과 같다.
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc(); // 1
myFunc(); // 2
//리턴된 displayName 함수를 실행(name 변수에 접근)
이 예제에서 displayName
함수는 클로저이고,name
은 비공개변수/자유변수이다. 또한 displayName
은 name
변수에 대한 클로저이다. 비공개변수의 조건은 클로저 함수의 매개변수도 아니고, 함수 내부에서 생성된 변수도 아니다.
실행 컨텍스트 관점에서 분석해보자. 전역 컨텍스트가 만들어진 뒤, 1
에서 makeFunc 함수의 호출과 동시에 makeFunc 함수 실행 컨텍스트가 만들어진다.
2
에서 myFunc 함수의 호출과 동시에 myFunc 함수 실행 컨텍스트가 만들어진다. myFunc 컨텍스트의 스코프 체인은 선언 당시의 렉시컬 환경을 따라가기 떄문에, 전역 컨텍스트와 makeFunc 컨텍스트를 포함한다. 따라서 makeFunc의 name
변수에 접근이 가능해진다.
이렇게 myFunc과 같이 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역변수에 접근할 수 있다. 이런 내부 함수와 그 내부함수가 선언될 당시의 환경을 클로저라 한다.
이 때 내부 함수는 외부함수에 있는 변수의 복사본이 아니라 실제 변수에 접근한다.
(function () {
statements
})();
IIFE를 변수에 할당하면 함수가 실행한 결과만 저장된다. 또한 IIFE로 호출된 함수는 호출 이후 바로 소멸된다.
const incleaseBtn = document.getElementById('inclease');
const count = document.getElementById('count');
const increase = (function(){
let counter = 0;
return function() {
return ++counter;
};
}()); // closure
incleaseBtn.addEventListner('click', ()=>{
count.innerHTML = increase();
})
이렇게 counter
를 클로저안의 비공개변수로 만들어 놓으면 increase
함수를 통하여 counter
를 업데이트 할수 있지만, 외부에서 직접 counter
에 접근할 수는 없기 때문에, 의도되지 않는 변형을 피할 수 있다.
class Counter() {
let counter = 0;
this.increase = function () {
return ++counter;
};
this.decrease = function () {
return --counter;
};
}
const counter = new Counter();
console.log(counter.increase());
만약 변수 counter를 this에 바인딩한 프로퍼티로 선언하였다면 외부에서 접근이 가능한 public 프로퍼티가 되지만, 일반적으로 선언된 변수는 Counter
밖에서 접근할 수 없다. 하지만, increase
, decrease
함수는 클로저이기 때문에 자신이 정의되었을 때의 환경인 counter
변수에Counter
밖에서 접근할 수 있게 된다.