다음 글은 생활코딩 - 클로저 글을 바탕으로 작성되었습니다.
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