클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수를 말한다.
위의 사진을 보면 클로저를 사용하였을때의 모습이다. 함수의 변수는 함수의 사용이 끝나면 그와 동시에 생명주기가 다하는 특성을 가지고 있다 하지만 위의 사진에서는 inner에 outerFunc를 실행시키고 그 값으로 innerFunc를 값으로 반환한다 하지만 아까 함수에서 선언된 변수는 함수의 사용이 끝나는 즉시 생명주기가 다 한다 하였는데 반환받은 inner를 실행시켜보면 마치 함수를 outerFunc의 x에 검색에 성공한다.
이처럼 자신을 포함하고 있는 외부함수보다 내부함수가 더 오래 유지되는 경우, 외부 함수 밖에서 내부함수가 호출되더라도 외부함수의 지역 변수에 접근할 수 있는데 이러한 함수를 클로저(Closure)라고 부른다.
그럼 이러한 클로저는 어떤 특징과 이점이 있을까. 우선 클로저는 아래와 같은 특징과 이점을 가진다. 상태유지 부터 자세히 알아 보자
1. 상태유지
2. 전역 변수의 사용 억제
3. 정보의 은닉
위와 같은 코드가 있다고 가정한다면 실행하였을때의 모습은 아래와 같다
우리는 toggle을 눌러 박스의 상태를 변화시킬 수 있는 코드를 짠 것이다. 하지만 이 코드는 클로저를 이용하여 상태를 기억하고 있는 코드이다. 만약 이런식으로 클로저를 지역변수를 사용 할 수도 있지만 지역변수로 표현하게된다면
위의 코드처럼 표현 할 수 있을것이다. 하지만 이또한 문제가 있는데 버튼을 클릭하게 된다면 이전의 상태를 기억하지 못하는 increase함수는 계속 1에서 넘어 갈 수 없을 것이다 이를 클로저를 이용하여 해결하여 보자
위의 코드는 클로저를 이용하여 표현한 코드이다 이대로 작성해보면 정상적으로 작동 하는 것을 확인 할 수 있을것이다 그 이유는 incerase의 즉시실행 함수는 실행이 끝나는 즉시 소멸하지만 즉시실행 함수가 반환한 함수는 자신이 만들어졌을때의 렉시컬 환경을 기억하기 때문에 클로저를 담고 있는 변수 inclease 버튼을 클릭하면 클릭 이벤트 핸들러 내부에서 호출된다. 이때 클로저인 이 함수는 자신이 선언됐을 때의 렉시컬 환경인 즉시실행함수의 스코프에 속한 지역변수 counter를 기억한다. 따라서 즉시실행함수의 변수 counter에 접근할 수 있고 변수 counter는 자신을 참조하는 함수가 소멸될 때가지 유지된다.
(처음 즉시실행 함수로 실행되고 increase에는 클로저가 담겨 있는 것이므로 아래의 버튼 클릭을 할때 increase()는 클로저를 실행하는 것이다.)
클로저의 정보은닉은 쉽게 말해서 외부에서는 접근 불가능한 특징을 말한다 이를 이용해 클래스 기반의 언어(Java, C++, C#, Python, PHP, Ruby, Object-C)의 private 기능을 흉내낼 수 있는 것이다.
해당 코드를 보면 함수 Counter안에 counter이라는 변수와 클로저 increase, decrease가 있다 여기서 맨 아래의 코드 console.log()를 보면 increase와 decrease는 생성자로 만든 counter를 이용하여 접근 할 수 있는것을 알 수 있을것이다. 하지만 Counter 함수 안에 counter에 접근하려고 하면 접근 할 수 없는데 그 이유는 counter는 this로 바인딩 된 변수가 아니기 때문이다 그래서 외부에서 counter를 이용하려고 하면 참조할 수 없지만 자신이 만들어진 렉시컬 환경을 기억하는 increase와 decrease를 이용하면 해당 변수에 접근이 가능한 것이다
그림의 출처,해당 글의 참고 사이트 - 참고사이트