자바스크립트를 공부하다 보면 흔히 접할 수 있는 단어 중 하나인 클로저! 콜백을 공부하다보면 접할 수도 있고, 전반적인 프로그래밍 언어를 공부할 때 등장하는 개념이기도 하다. 이 글은 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 |
댓글