콜백
처리의 위임
함수가 값으로 사용될 수 있는 특성을 이용하면 함수의 인자로 함수를 전달할 수 있다.
값으로 전달된 함수는 호출 될 수 있기 때문에 이를 이용하면 동작을 완전히 바꿀 수 있다.
예시) 객체에 속한 메소드(함수)를 이용해 이해해보자.
-
var numbers = [20, 10, 9,8,7,6,5,4,3,2,1]; alert (numbers.sort()); // [1, 10, 2, 20, 3, 4, 5, 6, 7, 8, 9]
결과를 보면 3보다 10이 먼저 나오는 등의 이상한 결과를 볼 수 있다.
이건 내장 함수인 sort 때문인데 sort의 정의를 보면
-
sort(sortfunc)
인자명 |
데이터형 |
필수/옵션 |
설명 |
sortfunc |
function |
옵션 |
원소들 간에 무엇이 우선인지를 판단한다 |
이와 같이 sort는 배열의 방식을 자신이 정할 수 있다.
정하지 않으면 기본 적인 동작을 하기 때문에 10이 3보다 먼저 나오는 것이다.
자세한 예를 들진 않고 결과만 설명하면 sort는 인자로 음수를 받게 되면 앞에 들어오는 수가 뒤에 오는 수 보다 작다고 인식한다.
Sort의 동작 방식과 콜백(처리 위임)을 사용하면 원하는 순서대로 나열 할 수 있다.
-
function sortNumber(a,b){ // 위의 예제와 비교해서 a와 b의 순서를 바꾸면 정렬 순서가 반대가 된다. return b-a; } var numbers = [20, 10, 9,8,7,6,5,4,3,2,1]; alert(numbers.sort(sortNumber)); // [20,10,9,8,7,6,5,4,3,2,1]
비동기 처리
콜백은 비동기처리에서도 유용하게 사용된다. 시간이 오래걸리는 작업이 있을 때 이 작업이 완료된 후에 처리해야 할 일을 콜백으로 지정하면 해당 작업이 끝났을 때 미리 등록한 작업을 실행하도록 할 수 있다.
해당 실습은 서버 환경에서만 동작하므로 영상을 참,
클로저
클로저(closure)는 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가르킨다.
내부, 외부 함수
-
function outter(){// 외부 함수의 시작 var title = 'coding everybody'; function inner(){// 내부 함수의 시작 alert(title); } // 내부 함수의 끝 inner(); } // 외부 함수의 끝 outter(); //coding everybody
위 예제를 보면 3. ~ 5. 까지가 내부 함수 이고 그것을 감싸고 있는 1. ~ 7. 까지가 외부 함수이다.
여기서 주목 하고 싶은 것은 외부 함수의 지역 변수인 title을 내부 함수에서 부를 수 있다는 것이다.
클로저의 특징
-
function outter(){ var title = 'coding everybody'; return function(){ alert(title); } } inner = outter(); inner(); // coding everybody
위 예제를 보면 7. 에서 outter()함수를 호출하고 return값으로 함수를 반환하고 inner라는 변수의 저장한다.
이후 8. 에서 inner()함수를 호출하면 “coding everybody” 라는 함수가 표현 된다.
여기서 눈여겨봐야 하는 것은 분명히 2. 에 있는 변수 title는 return을 했기에 4. 에서 호출하는alert(title); 를 실행 시킬 수 없어야 하지만 호출이 가능하다는 것이 클로저의 특징이다.
Ex) 클로저를 이용한 좀 더 실용적인 예제
-
function factory_movie(title){ return { get_title : function (){ return title; }, set_title : function(_title){ title = _title } } } ghost = factory_movie('Ghost in the shell'); matrix = factory_movie('Matrix'); alert(ghost.get_title()); // Ghost in the shell alert(matrix.get_title()); // Matrix set_title('공각기동대 '); alert(ghost.get_title()); // 공각기동대 alert(matrix.get_title()); // Matrix ~ 10. 까지는 get title와 set title 라는 함수를 가진 객체를 return하고 있다.
get title는 외부 함수가 받은 title라는 인자를 반환 하는 역할을 하고 (2. ~ 5.)
set title는 set title가 받은 _title를 외부 함수의 저장된 title에 넣는 역할을 한다. (6. ~ 8.)
- 에선 변수 ghost 에 “Ghost in the shell”라는 title을 가진 객체를 담고,
12. 에선 변수 matrix에 “Matrix”라는 title을 가진 객체를 담는다. - ~ 15. 19. ~ 20. 에서 처럼 이후 내장 함수인 get_title를 통해 저장된 title을 볼 수 있으며
- 에서처럼 내장 함수인 set_title를 통해 저장된 title을 변경 할 수 있다.
또한 여기서 만들어진 외부 함수의 title은 private변수가 되어 set_title이나 get_title으로만 변경/접근이 가능하다.
클로저의 응용
배열 arr[0 ~ 4] 까지에 0 ~ 4를 넣는 예제를 한번 만들어 보자.
-
var arr = [] for(var i = 0; i < 5; i++){ arr[i] = function(){ return i; } } for(varindex in arr) { log(arr[index]()); } // 5, 5, 5, 5, 5
얼핏 보면 2. 에서 for문을 돌면서i를 return 하여 arr[i]에 넣는 것처럼 보이지만 실행 결과는 5, 5, 5, 5, 5가 나오게 된다. 왜냐하면 4. 에서의 i값은 우리가 정의한 3. ~ 5. 함수의 외부 변수의 값이 아니기 때문이다.
그러므로 3. ~ 5.에게 외부 함수를 만들어 외부 변수를 참조하게 하면 제일 처음 원하는 결과를 얻을 수 있게 된다.
-
var arr = [] for(var i = 0; i < 5; i++){ arr[i] = function(id) { return function(){ return id; } }(i); } for(varindex in arr) { log(arr[index]()); } // 0, 1, 2, 3, 4
3. ~ 7. 외부 함수는 (i)를 인자로 받고 외부 변수 (id)에 값 넣어 5. 에서 그 값을 return한다.
그렇게 되면 arr[i] 값에는 우리가 원하는 0 ~ 4까지의 값이 들어가게 된다.
arguments (객체)
아래 예제를 보자
-
function sum(){ // 전달되는 인자가 없다. var i, _sum = 0; for(i = 0; i < arguments.length; i++){ write(i+' : '+arguments[i]+'<br />'); _sum += arguments[i]; } return _sum; } write('result : '+ sum(1,2,3,4)); // 전달되는 인자가 있다.
1. 을 보면 sum이라는 함수의 인자가 없어도 9. 에서처럼 인자를 전달 할 수 있다.
이게 가능한 이유는arguments라는 함수 안에서 사용할 수 있도록 전달 받은 인자들을 자동으로 배열에 넣어주는 기능을 가진 약속된 이름의 배열이 있기 때문이다.
매개변수의 수
-
function one(arg1){ log( 'one.length', one.length, 'arguments', arguments.length ); } one('val1', 'val2'); // one.length 1 arguments 2 functiontwo(arg1, arg2){ log( 'two.length', two.length, 'arguments', arguments.length ); } two('val1'); // two.length 2 arguments 1
7. 에서 one을 호출 할 때 2개의 인자를 보내고있고 one에서 지정된 매개 변수는 1개 이다.
이때 one.length와 결과와 arguments.length의 결과가 다른데 그 이유는 arguments는 매개 변수의 개수가 아닌 전달 받은 인자의 수만큼의 length를 가지고 있기 때문이다.
이를 이용해서 func.length값과 arguments.length 값을 비교해 정해진 매개변수만큼 인자가 왔는지 확인이 가능하다.