클로저의 개념 : "함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다."(from. MDN)
이 글만 봐서는 이해하기 어렵다. 어휘적(lexical) 환경의 조합이 무엇을 말하는지 알아보자.
const add = (x, y) => x + y;
add(2, 3); // 5
이 함수를 화살표를 한번 더 사용해서 만들어보자.
const add = x => y => x + y;
add(2)(3); // 5
이번에는 화살표가 두개가 되어 함수의 호출도 두번 이루어진다.
즉, add(2)의 리턴값은 계속 함수이다.
typeof add(2) // 'function'
add(2) // y => x + y (하지만 x의 값은 2로 이미 입력이 되어있다.)
//function 키워드를 사용하여 add화살표 함수를 변경해보면
const add = function(x) {
return function(y) {
return x + y;
}
}
클로저 함수는 이와같이 "함수를 리턴하는 함수"이다. 함수를 리턴하는 함수가 클로저의 형태를 만든다.
클로저는 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분된다. 클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는(closure; 폐쇄) 데에 있다. 따라서, 함수를 리턴하는 것만큼이나, 변수가 선언된 곳이 중요하다.
조금만 응용해보자, 전 시간에 공부했던 스코프도 개념인데. 범위를 닫는게 스코프를 한정시키것이랑 말이 같아보인다.. 말을 어렵게 꼬아놓은것 같다.
어쨋든 내부함수에서는 외부변수에 접근이 가능하지만, 외부변수에서는 내부함수에 선언된 내부함수의 내부변수에는 접근이 불가능하다는 것이다.
하지만 이것은 단지 데이터를 보존하는 함수를 설명하기 위한 기초였다!
일반적으로 함수는 실행이 종료되면 그 함수가 가지고 있던 내부변수를 외부에서 사용할 수 없다. 하지만 "클로저 함수"는 이와 다르게 실행이 끝나더라도 외부함수의 내부변수가 메모리 상에 저장이 된다.
const add = function(x) {
return function(y) {
return x + y;
}
}
const add5 = add(5); //함수 실행이 끝나도 5라는 값은 사용가능
add5라는 함수는 실행이 끝났음에도 5를 변수 x에 담은 채로 유지된다.
따라서 add5함수는 다음과 같이 사용도 가능하고, 보다 실용적으로 활용가능하다.
add5(7) // 12
add5(10) // 15
//클로저 모듈 패턴을 알아보자
const makeCounter = () => {
let value = 0;
return {
increase: () => {
value = value + 1
},
decrease: () => {
value = value - 1
},
getValue: () => value
}
}
const counter1 = makeCounter();
counter1 //{ increase: f, decease: f, getValue: f }
객체에 담아 여러 개의 내부 함수를 리턴.
makeCounter 함수를 바꾸지 않고, value라는 변수에 새로운 값을 할당하는 것은 불가능하다. 이것을 정보의 접근 제한(캡슐화)라고 한다.
하지만, 리턴하는 객체가 제공하는 메소드를 통해 'value'값을 간접적으로 조작 할 수 있다.
const counter1 = makeCounter();
counter1.increase();
counter1.decrease();
counter1.getValue();
const counter2 = makeCounter();
counter2.increase();
counter2.decrease();
counter2.getValue();
이와같이 함수 재사용성을 극대화하여, 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 모듈화라고 한다.
클로저를 통해 데이터와 메소드를 같이 묶어서 다룰 수 있다.
클로져는 "함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성 된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다." 라고 합니다. 여기서의 키워드는 "함수가 선언"된 "어휘적(lexical) 환경"입니다. 특이하게도 자바스크립트는 함수가 호출되는 환경와 별개로, 기존에 선언되어 있던 환경 - 어휘적 환경 - 을 기준으로 변수를 조회하려고 합니다. 유어클레스 영상에서 언급되는 "외부함수의 변수에 접근할 수 있는 내부함수"를 클로져 함수로 부르는 이유도 그렇습니다. 클로저 함수: 클로저는 외부함수의 컨텍스트에 접근할 수 있는 내부함수를 뜻합니다. 외부함수의 실행이 종료된 후에도, 클로저 함수는 외부함수의 스코프, 즉, 함수가 선언된 어휘적 환경에 접근할 수 있습니다. 클로저 사용 예시: 클로저를 통해 커링(currying, 함수 하나가 n개의 인자를 받는 대신 n개의 함수를 만들어 각각 인자를 받게 하는 방법), 클로저 모듈(변수를 외부 함수 스코프 안쪽에 감추어, 변수가 함수 밖에서 노출되는 것을 막는 방법) 등의 패턴을 구현할 수 있습니다. 클로저의 단점: 일반 함수였다면 함수 실행 종료 후 가비지 컬렉션(참고 자료: MDN '자바스크립트의 메모리 관리') 대상이 되었을 객체가, 클로저 패턴에서는 메모리 상에 남아 있게 됩니다. 외부 함수 스코프가 내부함수에 의해 언제든지 참조될 수 있기 때문입니다. 따라서 클로저를 남발할 경우 퍼포먼스 저하가 발생할 수도 있습니다. 자바스크립트는 가비지 컬렉션을 통해 메모리 관리를 합니다. 객체가 참조 대상이 아닐 때, 가비지 컬렉션에 의해 자동으로 메모리 할당이 해제됩니다.