1. 함수의 활용
1-1 클로저(closure)
클로저는 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가르킨다 하였다. 다음과 같다.
function outter(){
function inner(){
var title = 'hello world!';
alert(title);
}
inner();
}
outter();
// hello world!
inner메소드를 정의하고, 그것을 다시 감싸는 outter가 있는 구조로 되어있다. 이것이 내부함수인데, 자바스크립트는 함수 안에서 또다른 함수를 선언할 수 있기 때문에 이것이 가능한 것이다.( 함수가 값으로 치환되는것이 가능하기 때문)
이 개념은 다음과도 연결된다.
function outter(){
var title = 'coding everybody';
function inner(){
alert(title);
}
inner();
}
outter();
// hello world!
상기와 같다고 하였을때, hello world가 어째서 출력되는지에 대한 개념이 모호할 수 있다. 그것은 내부함수의 특징때문에 그런 것인데, 우선 내부함수 inner에는 title을 출력하려 하지만, 선언되어있지 않다. 이때, 여태까지 정리한 내용대로라면 전역변수에서 title을 찾는게 순리일 것인데, 내부함수에서는 다르다.
내부함수에서는 변수를 호출하였을 때 그 변수가 내부 함수 내에서 선언되어있지 않다면 그 값을 외부함수에서 찾아서 가져다 사용한다. 그렇기 때문에 상기 예제가 오류가 발생하지 않고 hello world가 출력될 수 있는 것이다.
또한, 내부함수는 외부함수가 종료되었을 때(return)도 내부함수를 호출함으로서 다시 외부함수에 접근할 수 있다. 그것이 클로저의 특징이다. 다음과 같다.
function outter(){
var title = 'hello world!';
return function(){
alert(title);
}
}
var inner = outter();
// hello world!
inner();
// hello world!
outter가 리턴으로 이미 종료되었더라도, inner 메소드를 호출하면 다시 outter메소드를 실행한것과 동일한 결과를 얻을 수 있다 이것이 바로 외부함수의 종료에도 불구하고 내부함수를 호출하였을 때 다시 외부함수를 호출할 수 있는, 클로저의 특징인 것이다.
자바를 학습하고 나서 자바스크립트의 복습을 진행할때, 함수의 생명이 끝나고(return이 완료되고) 함수가 다시 호출될수 없을 때, 라는 말을 제대로 이해하지 못하고 있었다. 자바는 클래스를 생성하고 그안에 메소드로서 함수를 생성하고, 객체를 만들어 호출하는 방식이었기 때문이다.
다시 생각을 해보니 여태까지의 예제들은 전부 절차지향이었고, 객체안의 메소드가 아닌 정의하고 리턴한 메소드기 때무문에 리턴이 되면 생명이 꺼진다 라는 의미가 무슨말인지 이해가 될 수 있었다.
하기의 예제가 그 내용이다.
function factory_movie(title){
return {
get_title : function (){
return title;
},
set_title : function(_title){
title = _title
}
}
}
ghost = factory_movie('A');
matrix = factory_movie('B');
alert(ghost.get_title()); // A
alert(matrix.get_title()); // B
ghost.set_title('C');
alert(ghost.get_title()); // C
alert(matrix.get_title()); // B
자바에선, 객체지향에서는 당연하였던 것들이다. 예제에서 title을 인자로 받는 factory_movie 메소드를 정의한 후 객체를 리턴하고 있다. 객체안에는 두개의 메소드가 정의되어있는데 하나는 get_title(title을 리턴한다.)이고, 다른 하나는set_title(title에 외부 상태주입을 받는다)이다.
그리고, ghost 라는 변수에 factory_movie라는 객체를 'A'라는 상태를 가진채 생성을하고, matrix라는 변수에는 'B'라는 상태를 가진채 생성을 한다. 그리고 두 변수를 호출하면, 각각 A와 B를 리턴할 것이다. 당연한 것이다.
그리고 해당 객체 안에 존재하는 set_title이라는 메소드를 호출하여 ghost변수의 상태에 c를 주입하게 된다면, 다시 재실행했을때는 'C'라는 값을 리턴하게 된다.
상기와 같은 상황에서 원래 factory_movie의 인자인 title은 스코프가 지역변수인 것이고, 절차대로 정의된뒤 종료되었기 때문에 다시 접근할 수 없는 즉, private한 변수가 되는 것이다. 필자가 이해한 바로는 이것이 객체지향 이전, 절차지향에서 객체지향적인 프로그래밍을 하기 위해 사용된 개념인 것 같았다. 예제의 코드들이 class의 것과 동작방식 및 생김새가 너무나 유사하기 때문이다.
2. 인자, Arguments
본 장에서는 자바스크립트 함수의 매개변수와 인자에 대한 학습 내용을 정리하였다.
2-1 arguments
인자와 매개변수를 정리하기 위하여 아주 간단한 예제를 작성해보았다.
function my_function( name ) { // 매개변수
return name + "hello world";
}
var name = "cs";
my_function( name ); // 인자
상기 예제는 my_function이라는 함수에서 name 이라는 매개변수 를 전달받아 처리한 후 리턴하는 예제이다.
my_function에서는 값을 처리하기 위해 name이라는 값을 받아야 하는데, 이때 함수에서 요구하는 name은 매개변수라고 한다. 함수가 호출될 때 매개변수를 전달해주어야 하는 상황이다.
함수가 정의되고 밑에 name이라는 변수에 "cs"라는 값을 넣고, 그 다음 my_function()을 호출하여 name을 전달해 주었는데 이때 전달해주는 변수를 인자라고 부른다.
즉 함수에서 값을 받을때는 매개변수, 함수로 값을 줄때는 인자라고 하는 것이다. 예제에 각주로서 표시를 해 두었다.
자바스크립트에서는 타언어와 다르게 함수가 매개변수를 받지 않아도, 값을 인자로 넘길 수 있다. 다음과 같다
function sum(){
var i, _sum = 0;
for(i = 0; i < arguments.length; i++){
document.write(i+' : '+arguments[i]+'<br />');
_sum += arguments[i];
}
return _sum;
}
document.write('result : ' + sum(1,2,3,4));
예제에서 sum이라는 메소드는 매개변수를 받지 않는다. 그럼에도 불구하고 메소드를 호출 하였을때. sum이라는 함수에 인자 4개를 부여한 것을 확인할 수 있다(1,2,3,4). 기존 학습하였던 php혹은 java였다면 분명 컴파일을 거부하는 사태까지 올 수 있을 예제이다. 그러나 자바스크립트는 오류없이 실행된다 하였다.
그 이유는 자바스크립트의 과한 친절 덕분이라고 하는데, 자바스크립트에서는 메소드에서 매개변수를 받지 않아도, 인자를 부여한다면, 그대로 값을 받아서 메소드를 실행한다고 하였다. 그렇다면 이 때 매개변수로 받지는 않았지만 전달받은 인자를 사용하고자 한다면, 그 값에 접근하고자 한다면 어떻게 해야 하는 것일까?
이 때는 argumets라는 객체를 사용하면된다. 배열과 유사하게 사용할 수 있는 이 객체는, 배열이 보유하고 있는 메소드를 유사하게 사용할 수 있다. 그리고 동작방법은 예상하는 바와 같다. sum을 호출할 때 받은 인자(여러개가 될 수 있다)를 arguments라는 객체에 주입하고, 그것을 배열의 형식으로 저장하여 꺼내 사용할 수 있도록 조치를 취해놓은 것이다.
상기의 내용과 관련하여 재미있는 예제가 있었는데, 다음과 같다.
function zero(){
console.log(
'zero.length', zero.length,
'arguments', arguments.length
);
}
function one(arg1){
console.log(
'one.length', one.length,
'arguments', arguments.length
);
}
function two(arg1, arg2){
console.log(
'two.length', two.length,
'arguments', arguments.length
);
}
zero();
// zero.length 0 arguments 0
one('val1', 'val2');
// one.length 1 arguments 2
two('val1');
// two.length 2 arguments 1
예제에서 zero는 비교를 위하여 정의하였으므로, 구분역할을 한다. one메소드를 보자 one 메소드는 매개변수를 하나만 받지만, 호출하는 부분에서는 두개의 인자를 전달하고 있다.
이 때, one이라는 메소드 내부에서 메소드 one의 길이(length)와, arguments의 길이(length)를 같이 출력하게 되는데, 그 결과를 보면 예제의 각주와 같이 one의 길이는 1, arguments의 길이는 2가된다.
즉, 메소드의 길이를 구하면, 몇개의 인자를 받았는지 조회할 수 있고, 해당 메소드의 arguments의 길이를 구하면, 실제로 전달된 인자의 갯수를 구할 수 있게 되는 것이다.
이렇게 자바스크립트의 함수지향까지의 학습을 하였다 다음 장부터는 자바스크립트의 객체지향의 공부를 시작할 예정이다.
'Language > JavaScript' 카테고리의 다른 글
공부내용 정리 :: JavaScript 기초 4 (0) | 2021.07.28 |
---|---|
공부내용 정리 :: JavaScript 기초 2 (0) | 2021.07.25 |
공부내용 정리 :: JavaScript 기초 1 (0) | 2021.07.23 |