내부함수가 외부함수의 맥락에 접근할 수 있는 것을 가르킴.
function outter(){
function inner(){
var title = 'coding everybody';
alert(title);
}
inner();
}
outter(); // coding everybody
외부함수인 outter 함수가 실행되면 내부함수인 inner가 실행되게 되는데 이때 alert(title)이 실행되어 alert창에 coding everybody가 출력되게 된다.
이를 closure 형태로 변경하면 다음과 같다.
function outter(){
var title = 'coding everybody';
function inner(){
alert(title);
}
inner();
}
outter();
//--------------------------------
function outter(){
var title = 'coding everybody';
return function(){
alert(title);
}
}
inner = outter();
inner();
이렇게 내부함수인 inner는 외부함수의 변수인 title에 접근할 수 있다.
2번째 예제를 보면 outter는 실행 및 반환되어 inner라는 변수에 담긴다.
이때 지역변수인 title은 return에도 없고 반환되었으니 소멸되는 것이 자연스럽지만, inner를 실행하면 전과 똑같은 결과가 나온다.
따라서 closure는
외부함수가 실행되어 반환되어도 내부함수가 외부함수의 변수에 접근할 수 있고,
외부함수는 외부함수의 지역변수를 사용하는 내부함수가 소멸될 때까지 남아있는 것을 의미한다.
다음 예제를 보자
function factory_movie(title){
return {
get_title : function (){
return title;
},
set_title : function(_title){
title = _title
}
}
}
ghost = factory_movie('Ghost in the shell');
/*
ghost = {
get_title : function() { return 'Ghost in the shell' },
set_title : function(_title) { 'Ghost in the shell' = _title }
}
*/
matrix = factory_movie('Matrix');
/*
martix = {
get_title : function() { return 'Matrix' },
set_title : function(_title) { 'Matrix' = _title }
}
*/
alert(ghost.get_title()); // Ghost in the shell
alert(matrix.get_title()); // Matrix
ghost.set_title('공각기동대');
/*
ghost = {
get_title : function() { return '공각기동대' },
set_title : function(공각기동대) { 'Ghost in the shell' = 공각기동대 }
// Ghost in the shell => 공각기동대
}
*/
alert(ghost.get_title()); // 공각기동대
alert(matrix.get_title()); // Matrix
factory_move는 title을 매개변수로 받아 get_title, set_title을 반환한다.
ghost는 get_title, set_title함수를 가지고 있고 get_title
호출 시 매개변수로 받은 'Ghost in the shell'
을 반환한다.
ghost는 get_title, set_title함수를 가지고 있고 get_title
호출 시 매개변수로 받은 'Matrix'
을 반환한다.
ghost.set_title을 실행하면 매개변수로 받은 '공각기동대'
가 title
이 되어 factory_movie 호출 시 매개변수로 '공각기동대'
를 받은 것과 같다.
여기서 알 수 있는 점은 다음과 같다.
- 클로저는 객체의 메소드에서도 사용할 수 있다. ghost와 matrix는 get_title, set_title을 메소드로 가지고 있다.
- 동일한 외부함수 안에서 만들어진 내부함수나 메소드는 외부함수의 지역변수를 공유한다. 예제의 메소드들은 외부함수인 factory_movie의 파라미터로 전달된 지역변수인 title을 공유하고 있다.
- 똑같은 외부함수를 가져도 독립된 객체를 갖는다. ghost와 matrix는 서로에게 영향을 주지 않는다.
- private 속성을 이용할 수 있다. title은 정의된 객체인 ghost나 matrix를 통해서만 접근할 수 있으므로 private 하다고 볼 수 있다.
응용예제는 대부분 for문을 예제로 든다.
var arr = []
for(var i = 0; i < 5; i++){
arr[i] = function(){
return i;
}
}
for(var index in arr) {
console.log(arr[index]());
}
생각은 당연히 0, 1, 2, 3, 4
가 찍힐 것 같지만 실상은 5, 5, 5, 5, 5
이다.
왜냐면 for문의 i가 var로 선언되어 있기 때문에 호이스팅되어 for문이 아닌 for문 바깥에 선언된 것처럼 바뀌기 때문이다.
우리의 예상대로 결과를 나타내려면 다음과 같이 변경하면 된다.
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]());
}
//or ==========================
var arr = []
for(var i = 0; i < 5; i++){
arr[i] = (function(id){
return id;
})(i);
}
for(var index in arr) {
console.log(arr[index]);
}
//or ==========================
var arr = []
for(let i = 0; i < 5; i++){
arr[i] = function(){
return i;
}
}
for(var index in arr) {
console.log(arr[index]());
}
출처 : 생활코딩 - closure