
다음 글은 생활코딩 - 클로저 글을 바탕으로 작성되었습니다.
closure는 내부함수가 외부함수의 context에 접근할 수 있는 것을 가리킨다.
다음의 코드를 살펴보자.
'내부함수는 외부함수의 지역변수에 접근할 수 있다'는 것이 무엇인지 와닿을 것이다.
function outter() {
var title = 'coding everybody';
function inner() {
alert(title);
}
inner();
}
outter();
<실행 결과>
(alert) coding everybody
외부함수가 실행이 끝나서 소멸된 이후에도 내부함수가 외부함수의 지역변수에 접근할 수 있는데, 이러한 매커니즘을
클로저라고 한다.
function outter() {
var title = 'coding everybody';
return function() {
alert(title);
}
}
inner = outter();
inner();
<실행결과>
(alert) coding everybody
inner = outter();에서inner에는outter()의 return 값인 이름 없는 함수가 담긴다.
그 다음 줄의inner();로 넘어오면,outter은 이미return을 끝마치고 함수의 실행이 끝났으므로, 이 함수의 지역변수가 소멸되는 것이 자연스럽다.하지만 맨 마지막 줄을 실행했을 때, coding everybody가 실행된 것은,
외부함수의 지역변수인title이 소멸되지 않았음을 의미힌다.
클로저란, 내부함수가 외부함수의 지역변수에 접근할 수 있고,
외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸할 때까지 소멸하지 않는 특성을 의미한다.
function factory_movie(title) {
return {
get_title : function () {
return title;
},
set_title : function(_title) {
title = _title
}
}
}
closure를 이용하여, 영화의 제목을 저장하고 있는 객체를 정의하고 있다.
return되는 객체 안에 정의된 함수들은, factory_movie의 내부함수로 볼 수 있다.
매개변수 또한 지역변수이므로, 아래의 두 내부함수들에서 title의 값을 참조할 수 있다.
여기서 특이한 점은,
set_title 내의 함수에서의 title은 매개변수 title을 참조하고 있으므로, 이 값이 바뀌면 factory_movie의 매개변수 title또한 변하게 된다.
또한, get_title과 set_title은 서로 외부함수인 factory_movie의 지역변수인 title을 서로 공유하게 된다.
let ghost = factory_movie('Ghost in the shell');
let matrix = factory_movie('Matrix');
위의 두 변수
ghost와matrix에는 각각get_title과set_title이라는 메소드를 담고 있는 컨테이너인 객체가 담겨있다.
console.log(ghost.get_title());
console.log(matrix.get_title());
<실행 결과>
Ghost in the shell
Matrix
ghost와matrix에는 각각 자신들이 실행될 때의 context에서의 외부함수의 지역변수가 유지되고 있고, 그것에 접근할 수 있다.
ghost.set_title('공각기동대');
console.log(ghost.get_title());
console.log(matrix.get_title());
공각기동대
Matrix
ghost.set_title()로title값을 바꾸어도,ghost객체가 접근할 수 있는title값 만을 바꿀 뿐,matrix객체가 접근할 수 있는title에는 아무런 영향을 미치지 않음을 확인할 수 있다.
' private 변수 '
get_title과 set_title이 내부적으로 사용하는 변수 title은
외부함수인 factory_movie의 매개변수 title을 참조한다.
factory_movie함수는 객체를 return하면서 생이 마감하였기 때문에, get_title과 set_title을 통해서만 title에 접근할 수 있다.
많은 data가 소프트웨어 내에서 존재하게 되는데 누구나 수정할 수 있는 형태의 데이터가 된다는 것은, 결국 그 소프트웨어가 망가질 가능성이 크다는 뜻이다.
이번의 경우 역시,
get_title과set_title로만title에 접근할 수 있기 때문에, 외부에서 title이라는 변수를 외부에서 어떻게 사용하든 간에 안전하게 유지할 수 있다.
또한 , 아래와 같이
function factory_movie(title) {
return {
get_title : function () {
return title;
},
set_title : function(_title) {
if (typeof _title === 'String') {
title = _title
} else {
alert('제목은 문자열이어야 합니다.');
}
}
}
}
조건을 생성해 주면, title 변수가 조금 더 안전하게 수정될 수 있다.
여기에서 다룬 주제와 동일하다
var arr = []
for(var i = 0; i < 5; i++){
arr[i] = function(){
return i;
}
}
for (var index in arr) {
console.log(arr[index]());
}
<실행결과>
5
5
5
5
5
아래의 코드로 변경해야 정상적으로 동작한다.
var arr = []
for(var i = 0; i < 5; i++){
arr[i] = function(id) {
return function(){
return id;
}
}(i);
}
for(var index in arr) {
console.log(arr[index]());
}
<실행결과>
0
1
2
3
4