클로저의 정의
클로저란 어떤 함수 A에서 선언한 변수 a 를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상을 말합니다.
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
}
return inner;
};
var outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3
outer2 변수는 outer 의 실행 결과인 innr 함수를 참조하게 될 것입니다.
이후 9번째에서 outer2 를 호출하면 앞서 반환된 함수인 inner가 실행되겠죠.
inner 함수의 실행 시점에는 outer 함수는 이미 실행이 종료된 상태라서 outer 함수의 LexicalEnvironment 에 접근이 불가능 할 것입니다. 그런데 어떻게 접근을 할 수 있었을까요?
이유는 바로, 가비지 컬렉터의 동작 방식 때문입니다.
가비지 컬렉터는 어떤 값을 참조하는 변수가 하나라도 있다면 수집 대상에 포함시키지 않습니다. outer 의 실행이 종료되더라도 inner 함수는 언젠가 outer2를 실행함으로써 outer 안의 값에 접근할 가능성이 열린 것이죠. 그러므로 수집 대상에서 제외 됩니다.
클로저와 메모리 관리
'메모리 누수' 라는 표현은 개발자의 의도와 달리 어떤 값의 참조 카운트가 0이 되지 않아 GC(Garbage Collector)의 수거 대상이 되지 않는 경우에는 맞는 표현이지만, 개발자가 의도적으로 참조 카운트를 0이 되지 않게 설계한 경우는 '누수'라고 할 수 없겠죠.
참조 카운트를 0으로 만드는 방법은? 식별자에 참조형이 아닌 기본형 데이터(보통 null 이나 undefined)를 할당하면 됩니다.
var outer = function () {
var a = 1;
var inner = function () {
return ++a;
}
return inner;
};
var outer2 = outer();
console.log(outer2()); // 2
console.log(outer2()); // 3
outer = null;
클로저 활용 사례
1. 콜백 함수 내부에서 외부 데이터를 사용하고자 할 때
방법 1. 콜백 함수를 내부함수로 선언해서 외부변수를 직접 참조하는 방법
방법 2. bind 메서드로 값을 직접 넘겨주는 방법
방법 3. 콜백 함수를 고차함수로 바꿔서 클로저를 활용한 방법
고차함수란?
함수를 인자로 받거나 함수를 리턴하는 함수이다.
2. 접근 권한 제어 (정보 은닉)
자바스크립트는 변수 자체에 접근 권한 (public, private, protected) 을 직접 부여하도록 설계돼 있지 않다.
클로저를 이용하여 public 한 변수와 private 한 값을 구분할 수 있다.
var createCar = function () {
var fuel = Math.ceil(Math.random() * 10 + 10);
var moved = 0;
return {
get moved() {
return moved;
},
run: function () {
var km = Math.ceil(Math.random() * 6);
var wasteFuel = km / 10;
fuel -= wasteFuel;
moved += km;
console.log(km + "km 이동 , 남은 연료 : " + fuel);
}
};
};
var car = createCar();
car.run(); // 3km 이동 , 남은 연료 17.3
console.log(car.moved); // 3
console.log(car.fuel); // undefined
car.fuel = 1000;
console.log(car.fuel); // 1000
car.run(); // 1km 이동, 남은 연료 17
car.moved = 1000;
console.log(car.moved); // 4
1. (car.moved) 가 출력되는 이유는 getMethod 때문
2. car.fuel = 1000; 이라는 의미는 car 객체에 새로운 fuel 이라는 프로퍼티를 추가하는 행위를 하는 것이다. 따라서 createCar() 내부에 실제 fuel 이라는 변수에는 접근 하는 것이라고는 볼 수 없다.
3. 부분 적용 함수
부분 적용 함수 : n 개의 인자를 받는 함수에 미리 m개의 인자만 넘겨 기억시켰다가, 나중에 (n-m) 개의 인자를 넘기면 비로소 원래 함수의 실행 결과를 얻을 수 있게끔 하는 함수입니다.
미리 일부 인자를 넘겨두어 기억하게끔 하고, 추후 필요한 시점에 기억했던 인자들까지 함께 실행하게 한다는 개념 자체가 클로저의 정의에 정확히 부합한다.
4. 커링 함수
커링 함수 : 여러 개의 인자를 받는 함수를 하나의 인자만 받는 함수로 나눠서 순차적으로 호출될 수 있게 체인 형태로 구성한 함수 이다.
커링은 한 번에 하나의 인자만 전달하는 것을 원칙으로 합니다.
마지막 인자가 전달되기 전까지는 원본 함수가 실행되지 않습니다.
부분 적용 함수와 커링 함수의 차이점
부분 적용 함수 : 여러 개의 인자를 전달할 수 있고, 실행 결과를 재실행할 때 원본 함수가 무조건 실행된다.
커링 함수 : 한 번에 하나의 인자를 전달하고, 그 다음 인자를 받기 위해 대기하며, 마지막 인자가 전달될 때 원본 함수가 실행된다.
var curry3 = function (func) {
return function (a) {
return function (b) {
return func(a,b);
};
};
};
var getMaxWith10 = curry3(Math.max)(10);
console.log(getMaxWith10(8)); // 10
console.log(getMaxWith10(25)); // 25
'자바 스크립트' 카테고리의 다른 글
[코어 자바스크립트 스터디] 7주차. 클래스 (0) | 2022.01.06 |
---|---|
[코어 자바스크립트 스터디] 6주차. 프로토타입 (0) | 2021.12.23 |
[코어 자바스크립트 스터디] 1주차. 데이터 타입 (0) | 2021.12.03 |