자바스크립트를 공부하다 보면 흔히 접할 수 있는 단어 중 하나인 클로저! 콜백을 공부하다보면 접할 수도 있고, 전반적인 프로그래밍 언어를 공부할 때 등장하는 개념이기도 하다. 이 글은 mdn 클로저 문서를 보고 공부하며 적은 글입니다 ㅎㅎ..
클로저
클로저란 함수와 함수가 선언된 어휘적 환경(Lexical scoping)의 조합이다.
MDN 에서는 이렇게 클로저를 정의하고 있다. 그렇다면 어휘적 환경, Lexical scoping 은 뭘까? 쉽게 말하면 변수들의 범위를 어휘적으로 지정하겠다는 말이다. 즉 지역변수의 스코프(범위)를 어디에 선언했는지에 따라 결정하는 것. 예제를 보자.
function init() {
var name = "구운밤";
function displayName() {
console.log (name);
}
displayName();
}
init();
위에서 name 변수와 displayName 함수는 같은 init 이라는 function의 내부에서 생성되었다. 즉 스코프가 init 함수의 내부인데, 위 예제를 보면 displayName 함수 내부에서 name 변수를 사용하고 있다. 위를 실행하면 제 이름이 잘 출력이 되는 것을 볼 수 있다.
위는 lexical scoping의 대표적인 예시인데, 위 예제에서도 알 수 있듯이 lexical은 변수가 코드 내 어디에 선언되었는지에 따라 사용 가능한 범위가 지정됨을 말한다. 자바스크립트에서는 함수 내부에서 외부(부모) 함수의 변수에 접근할 수 있기 때문에 변수 name에 접근할 수 있는 것이다. 하지만 이때, 만약 displayName 함수 내부에 같은 이름의 변수가 또 있었다면 this.name, 내부의 변수가 사용됩된다.
클로저가 뭔데?
이번엔 다른 예제를 통해 알아보자.
function makeAdder(x) {
var y = 1;
return function(z) {
y = 100;
return x + y + z;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 107 (x:5 + y:100 + z:2)
console.log(add10(2)); // 112 (x:10 + y:100 + z:2)
위 예제에서는 먼저 makeAdder라는 함수를 정의했다. 파라미터 x를 받아 y, z 값을 더한 값을 리턴하는 함수란 걸 쉽게 알 수 있는데, 위에서 설명한 것처럼, 동일한 변수 y가 외부와 내부에 동시에 있으면 내부의 변수를 사용하게 된다. 최종 계산 시에는 y는 100!
그 밑에 변수 add5, add10 에 위 함수에 5, 10 이라는 값을 담은 함수를 저장한다. 자바스크립트에서는 함수를 변수에 리턴함으로써 저장할 수 있는데, 이 리턴하는 함수가 클로저를 형성하게 된다. 이 둘은 클로저인데, 위의 정의처럼 함수와 함수가 선언된 어휘적 환경을 저장하게 된다. 쉽게 말해, 둘의 함수 내용은 같지만 다른 환경을 저장하는 거죠. 함수가 실행되면 add5이라는 클로저 내부에서는 x가 5라는 값을 갖지만, add10의 맥락적 환경에서 x 는 10이다.
클로저의 사용
1. 모듈 패턴
먼저 클로저를 이용해 프라이빗 메소드를 흉내낼 수 있다. 프라이빗 메소드를 사용하면 변수에 제한적인 접근만을 허용하여 보안적으로나 코드 인터페이스 관리를 쉽게 할 수 있도록 도와준다. 원래 자바스크립트는 메소드를 프라이빗으로 선언할 수 없죠. 아래 예제를 통해 어떻게 흉내내는지 알아보자.
var counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
};
})();
console.log(counter.value()); // logs 0
counter.increment();
counter.increment();
console.log(counter.value()); // logs 2
counter.decrement();
console.log(counter.value()); // logs 1
위 예제에서는 counter.increment, counter.decrement, counter.value 세 함수에 의해 공유되는 하나의 어휘적 환경을 만든다. 카운터 변수 에 저장된 익명환경 안에서 어휘적 환경이 만들어지고, 정의되는 즉시 이 함수가 실행되는데, 이 환경은 변수 하나와 함수 하나를 가지고 있다. 이는 외부에서 접근할 수 없고 익명 함수에서 반환된 세 개의 퍼블릭 함수를 통해서만 접근가능하므로, 프라이빗 메소드를 흉내내는 것과 같다. 여기서 increment, decrement, value 는 같은 환경을 공유하는 클로저이다. 위를 실행하면 카운터가 잘 작동하는 것을 볼 수 있다. 이처럼 클로저를 잘 활용하면 객체지향 프로그래밍의 캡슐화, 정보 은닉 같은 이점을 얻을 수 있다.
참고 - mdn
'Develop > 백엔드 & 서버' 카테고리의 다른 글
| Javascript는 비동기를 어떻게 처리해 - async await (0) | 2021.01.22 |
|---|---|
| Javascript는 비동기 함수를 어떻게 처리해 - 프로미스 (0) | 2021.01.20 |
| Javascript는 비동기를 어떻게 처리해 - 콜백함수 (0) | 2021.01.20 |
| Javascript는 비동기를 어떻게 처리해 - 동작 원리 (0) | 2021.01.19 |
| CORS 이슈 해결하기 (0) | 2021.01.18 |
댓글