자바스크립트 완벽 가이드/ 함수

함수 정의와 호출

함수는 임의 개수의 전달인자를 가질 수 있으며 return 문을 반드시 사용할 필요는 없다. return 문이 없으면 단순히 함수 몸체를 이루는 문장들을 하나씩 실행한 후에 undefined 값을 호출자에게 반환한다.

자바스크립트는 데이터 타입 제약이 느슨한 언어이기 때문에 함수 매개변수의 데이터 타입을 명시하지 않아도 좋다. 자바스크립트는 함수가 기대하는 타입의 데이터를 전달하는지 검사하지도 않는다. 만일 전달인자의 데이터 타입이 중요하다면 typeof 연산자를 사용하여 직접 테스트할 수 있다. 또한 자바스크립트는 정확한 개수의 전달인자를 전달하는지도 검사하지 않는다. 만약 함수가 기대하는 개수보다 많은 수의 전달인자를 전달하면 함수는 이런 추가분의 전달인자들을 무시한다. 만약 함수가 기대하는 개수보다 적은 수의 전달인자를 전달하면 빠뜨린 매개변수에는 undefined 값이 할당된다.

중첩된 함수

자바스크립트에서 함수는 다른 함수 안에 중첩되어 정의될 수 있다.

function hypotenuse(a, b) {
    function square(x) { return x*x }
    return Math.sqrt( square(a) + square(b) );
}

중첩된 함수는 그 함수가 중첩되어 위치하는 함수의 최상위 레벨에서만 정의될 수 있다. 즉, if 문이나 while 루프의 몸체 같은 문장 블록 안에서는 정의될 수 없다. 이런 제약은 오로지 function 문에 의한 함수 정의에만 해당한다. 함수 리터럴은 어디에든 위치할 수 있다.

함수 리터럴

함수 리터럴의 문법은 문장이 아니라 표현식으로 사용된다는 것과 함수 이름이 필요 없다는 것을 제외하면 function 문과 매우 유사하다. 아래의 두 코드는 거의 동일한 함수를 정의하는 예이다.

function f(x) { return x*x } // function 문
var f = function(x) { return x*x }; // 함수 리터럴

함수 리터럴은 비록 이름 없는 함수를 생성하지만 함수 리터럴의 문법은 선택적으로 함수 이름을 지정하는 것도 허용한다. 이는 재귀 함수를 작성할 때 유용하다.

var f = function fact(x) { if ( x <= 1) return 1; else return x*fact(x-1); };

위의 코드는 이름 없는 함수를 생성하고 이 함수에 대한 참조를 변수 f에 저장한다. 함수에 대한 참조를 fact 변수에 저장하지는 않지만 함수의 몸체 안에서 자신을 참조하기 위해 이 이름을 사용하는 것은 허용한다.

함수 리터럴은 자바스크립트 문장이 아니라 표현식으로 생성된다. 따라서 함수 리터럴은 매우 유연하며, 또한 한 번만 사용되고 버려지기 때문에 이름 붙이지 않아도 되는 일회용 함수를 정의하는데 적합하다. 예를 들어 함수 리터럴 표현식에 의해 기술된 함수는, 변수에 저장될 수도 있고 다른 함수에 전달인자로써 전달될 수도 있으며 곧바로 호출될 수도 있다.

f[0] = function(x) { return x*x }; //함수를 정의하여 이를 변수에 저장한다.
a.sort( function(a, b) { return a-b; } ); //함수를 정의하여 이를 다른 함수에 전달한다.
var tensquared = ( function(x) { return x*x; } ) (10); 정의하여 바로 호출한다.

함수 이름 붙이기

모든 적법한 자바스크립트 식별자가 함수의 이름으로 사용될 수 있다.

함수 전달인자

생략 가능한 전달인자(Optional Arguments)

때로는 함수 호출 시점에 전달인자를 생략할 수 있게 함수를 작성하는 것이 유용할 수도 있다. 이를 위해선 호출 당시에 생략될 수 있는 (또는 null로 지정된) 전달인자에 대해 적당한 기본값을 할당해 줄 수 있어야한다.

가변 길이 전달인자 목록: 전달인자 객체

함수의 몸체에서 식별자 arguments는 특별한 의미를 지닌다. arguments는 Arguments 객체를 참조하는 특별한 프로퍼티다. Arguments 객체는 배열과 유사한 객체로서 함수에 전달된 전달인자의 값을 전달인자 이름이 아니라 숫자를 사용해 접근하기 위한 방법으로 제공한다.

자바스크립트 함수는 비록 고정된 개수의 이름 붙은 전달인자들로 정의되지만 호출 시점에서는 이 고정된 개수와는 상관없이 임의 개수의 전달인자들을 건네받을 수 있다. Arguments 객체는 이름이 붙어있든 없든 상관없이 건네받은 모든 전달인자의 값에 접근하기 위한 방법을 제공한다. 한 개의 전달인자 x를 받는 함수 f를 정의한다고 가정하자. 만약 이 함수를 두 개의 전달인자와 함께 호출한다면 첫 번째 전달인자는 매개변수 이름 x나 argument[0]으로 접근할 수 있다. 두 번째 전달인자는 이름이 없으므로 arguments[1]로만 접근할 수 있다. 또한 arguments에는 실제 배열처럼 원소들의 수를 명시하는 length 프로퍼티가 있다. 두 개의 전달 인자와 함께 호출된 함수 f의 몸체 안에서 arguments.length는 2이다.

arguments 객체는 여러모로 유용하다. 자바스크립트는 전달인자 개수를 검사해 주지 않기 때문에 arguments 객체를 사용해서 직접 검사해야 한다.

또한 arguments 객체는 자바스크립트 함수의 중요한 가능성을 열어준다. 자바스크립트 함수는 임의 개수의 전달인자와도 작동할 수 있게 작성될 수 있다.

arguments가 실제로는 배열이 아니라 Arguments 객체라는 것을 기억하라. 각 Arguments 객체는 숫자 인덱스가 붙은 배열 원소들과 length 프로퍼티를 정의하지만 이는 그냥 우연히 번호가 붙은 몇 개의 프로퍼티를 소유한 객체라고 생각하는 편이 낫다.

Arguments 객체에는 별난 특징이 하나 있다. 만약 함수에 이름 붙은 전달인자가 있으면 Arguments 객체의 배열 원소는 함수 전달인자를 담은 지역 변수의 별칭이 된다. arguments[ ] 배열과 이름 붙은 전달인자는 동일한 변수를 참조하는 두 가지 다른 방법이다. 전달인자 이름을 사용하여 전달인자의 값을 변경하면 arguments[ ] 배열을 통해 읽어 들이는 값도 변한다. 거꾸로 말하면 arguments[ ] 배열을 사용하여 전달인자의 값을 변경하면 전달인자 이름을 통해 읽어 들이는 값도 변한다.

callee 프로퍼티

Arguments 객체는 배열 원소 뿐만 아니라 현재 실행되고 있는 함수를 가리키는 callee 프로퍼티를 추가로 정의한다. 이 프로퍼티는 거의 사용되지 않지만 이 프로퍼티를 사용하면 이름 없는 함수도 자기 자신을 재귀적으로 호출할 수 있다.

객체 프로퍼티를 전달인자로 사용하기

만약 함수에 전달인자가 세 개 이상 필요하다면, 함수를 호출할 때 전달할 인자들의 올바른 순서를 기억하는 일이 어려워진다. 함수를 호출할 때마다 함수에 대한 문서를 참조해야 하는 곤란에서 벗어나려면, 전달인자를 순서에 상관없이 이름과 값의 쌍으로 전달하여 주는 방법을 제공하라. 이러한 방식의 함수 호출을 구현하려면 우선 하나의 객체를 전달인자로 받는 함수를 정의하고 함수의 사용자로 하여금 함수에서 필요로 하는 이름과 값의 쌍들을 객체 리터럴로 정의하여 전달하게 하면 된다.

전달인자 데이터 타입

자바스크립트는 매우 유연하고 데이터 타입 제약이 느슨한 언어라서 때로는 함수가 건네받은 전달인자들의 개수와 데이터 타입에 대해 유연하게 대처할 수 있는 함수를 작성하는 것이 적절할 수 있다.

데이터로서의 함수

자바스크립트에서 함수는 문법일 뿐만 아니라 데이터이기도 하다. 즉 함수는 변수에 할당되거나 객체 프로퍼티와 배열 원소들에 저장될 수 있고 함수의 전달인자 등으로도 사용될 수 있다.

var a = square(4); // a에는 숫자 16이 저장된다.
var b = square( ); // 이제 b는 square 같은 함수를 가리킨다. 
var c = b(5); // c에는 숫자 25가 저장된다.

함수는 전역 변수 뿐만 아니라 객체 프로퍼티에도 할당될 수 있다. 이렇게 객체 프로퍼티에 할당된 함수를 메서드라 부른다.

var o = new Object;
o.square = function(x) { return x*x } // 함수 리터럴
y = o.square(16); // y에는 256이 저장된다.

배열 원소에 함수를 할당하는 경우에 함수는 심지어 이름조차 필요로 하지 않는다.

var a = new Array(3);
a[0] = function(x) { return x*x; }
a[1] = 20;
a[2] = a[0]( a[1] ); // a[2]에는 400이 저장된다.

메서드로서의 함수

메서드는 객체 프로퍼티에 저장되어 객체를 통해 호출할 수 있는 자바스크립트 함수에 지나지 않는다. 함수는 데이터 값이며 함수가 정의되어 저장된 이름에는 특별한 것이 없다는 사실을 상기하라. 함수는 어떠한 변수나 객체의 프로퍼티에도 저장될 수 있다. 만약 함수 f와 객체 o가 있다면 메서드 m을 다음과 같은 방법으로 정의할 수 있다.

o.m = f;

객체 o의 정의된 메서드 m( )은 다음과 같이 호출할 수 있다.

o.m( );

메서드에는 중요한 프로퍼티가 하나 있다. 호출된 메서드가 속하여 있는 객체는 메서드 몸체 안에 this라는 키워드의 값으로 저장된다. 따라서 o.m( ) 메서드를 호출할 때 메서드의 몸체 안에서는 객체 o를 this 키워드로 가리킬 수 있다.

this 키워드는 중요하다. 메서드로 사용되는 함수는 그 메서드가 속해 있는 객체를 암묵적 전달인자로 건네 받는다. 대체로 메서드는 그 메서드가 속해 있는 객체에 대해서 무엇인가 연산을 수행하기 때문에, 메서드 형태로 함수를 호출하는 구문은 그 함수가 객체와 관련하여 작동한다는 사실을 표현하는 세련된 방법이라 할 수 있다.

만약 함수를 메서드로서가 아니라 함수로 호출했다면 this 키워드는 전역 개체를 가리킨다. 혼란스럽게도, 메서드로 호출된 메서드 안에서 중첩된 함수를 호출해도 this 키워드는 전역 개체를 가리킨다. 중첩된 함수를 포함하는 함수의 내부에서는 고유한 값인 반면 중첩된 함수의 내부에서는 전역 객체를 가리킨다.

this가 변수 이름이나 프로퍼티 이름이 아니라 키워드임을 주의하라

생성자 함수

생성자 함수는 객체의 프로퍼티들을 초기화하는 함수이며 new 연산자와 함께 사용될 의도로 작성된다. new 연산자는 새로운 객체를 생성하고 이 새롭게 생성된 객체를 this 키워드의 값으로 하여 생성자 함수를 호출한다.

함수 프로퍼티와 메서드

함수는 특수화된 종류의 자바스크립트 객체다. 함수도 객체이기 때문에 Date나 RegExp 객체처럼 프로퍼티와 메서드가 있다.

length 프로퍼티

함수 그 자체의 length 프로퍼티는 함수가 건네받기를 기대하는 전달인자의 개수를 반환한다. 즉, 함수 매개변수 목록에 선언된 매개변수의 개수를 반환한다. 이는 함수가 건네 받은 전달인자의 개수를 명시하는 arguments 배열의 length 프로퍼티와 구분된다.

prototype 프로퍼티

모든 함수에는 미리 정의된 prototype 객체를 가리키는 prototype 프로퍼티가 있다. 이 prototype 객체는 함수가 new 연산자를 통해 생성자로 사용될 때, 새 객체를 정의하는 과정에서 매우 중요한 역할을 수행한다.

나만의 함수 프로퍼티 정의하기

함수 호출의 경계를 넘어 존재가 유지되는 변수를 사용해야 할 때가 있다. 이 때엔 전역 변수를 정의하여 네임스페이스를 지저분하게 하는 대신 Function 객체의 프로퍼티를 사용하는 것이 유용할 수 있다.

uniqueInteger.counter = 0; // 함수 밖에서도 살아 있어야 할 변수를 함수의 프로퍼티로 선언하고 초기화. 이는 함수 선언 전에도 가능하다.
function uniqueInteger( ) {
    return uniqueInteger.counter++;
}

apply( )와 call( ) 메서드

이 메서드를 사용하면 함수가 마치 다른 어떤 객체의 메서드인 것처럼 호출할 수 있다. call( )과 apply( ) 메서드의 첫 번째 전달인자는 함수가 소속되어 호출될 객체를 지정하며 이 전달인자는 함수 몸체 안에서 this 키워드의 값이 된다. call( ) 메서드의 나머지 전달인자들은 함수가 호출될 때 함수의 전달인자로 건네진다.

f.call( o, 1, 2 ); // 이러면 함수 f는 전달인자 1, 2를 갖고 객체 o의 메서드가 된다.

apply( ) 메서드는 call( ) 메서드와 유사하지만 함수로 건네줄 전달인자들을 배열로 지정한다는 점이 다르다.

f.apply( o, [1, 2] );

유용한 함수들

객체용 함수들

  • getPropertyNames( /* object */ o )
    • 객체 o의 열거 가능한 프로퍼티들의 이름을 담은 배열을 반환한다.
  • copyProperties( /* object */ from, /* optional object */ to )
    • 객체 from의 열거 가능한 프로퍼티들을 객체 to로 복사한다. 만일 to가 null 이면 새로운 객체를 생성한다. 이 함수는 결과로 to를 반환하거나 새롭게 생성한 객체를 반환한다.
  • copyUndefinedProperties( /* object */ from, /* object */ to )
    • 객체 from의 열거 가능한 프로퍼티들을 객체 to로 복사하되, to에 정의되지 않은 프로퍼티만 복사한다. 이 함수는 to에 미리 정의되어 있지 않은 값들에 대해 from에 저장해 둔 기본값들을 사용하려 할 때에 유용하다.

배열용 함수들

  • filterArray( /* array */ a, /* Boolean function */ predicate)
    • 배열 a의 각 원소를 지정된 술어(predicate) 함수로 전달한다. 술어 함수가 true를 반환한 원소들로 이루어진 배열을 결과로서 반환한다.
  • mapArray( /* array */ a, /* function */ f )
    • 배열 a의 각 원소를 지정된 함수 f로 전달하여 얻은 결과들을 원소로 하는 배열을 반환한다.

함수용 함수들

  • bindMethod( /* object */ o, /* function */ f )
    • 함수 f를 객체 o의 메서드로 하여 호출하는 독립형(standalone) 함수를 반환한다. 이것은 메서드를 함수에 전달하려 할 때 유용하다. 만약 함수를 그 함수의 객체와 연결하지 않으면, 그 연관 관계는 소실되며 전달한 메서드는 일반 함수처럼 호출된다.
  • bindArguments( /* functon */ f, /* initial arguments… */ )
    • 함수 f를 지정된 전달인자와 함께 호출해 주는 함수를 반환한다. 이렇게 반환된 함수는 또한 추가적인 전달인자들과 함께 호출될 수 있다.

함수 유효 범위와 클로저

어휘적 유효 범위(Lexical Scoping)

자바스크립트의 함수들은 동적이라기보단 어휘적으로 유효범위가 정해진다. 이것은 함수가 실행되는 유효범위가 아니라 함수가 정의되어 있는 유효범위 안에서 실행됨을 의미한다. 함수가 정의될 때는 현재의 유효범위체인이 저장되며 이것은 함수의 내부 상태 중 일부가 된다. 최상위 레벨에서 유효범위체인은 단순히 전역 객체들로 구성되며 어휘범위는 특별히 의미를 지니지 않는다. 그러나 중첩된 함수를 정의하면 유효범위는 함수를 포함한다. 즉, 이는 중첩된 함수가 그 함수를 포함하는 함수의 모든 전달인자와 지역변수들에 접근할 수 있음을 의미한다.

호출 객체

자바스크립트 인터프리터가 함수를 호출할 때엔 먼저 유효범위를 함수가 정의될 당시의 효력을 지니는 유효범위체인으로 설정한다. 그 다음에는 호출 객체로 알려진 새로운 객체를 생성하여 유효범위체인의 맨 앞에 추가한다. 이 호출 객체는 함수의 Arguments 객체를 가리키는 arguments 프로퍼티로 초기화된다. 그 다음에는 함수의 이름 붙은 매개변수들이 호출 객체에 추가되고, 함수 안에서 var 문장으로 선언된 모든 지역 변수가 역시 호출객체 안에 정의된다. 이 호출객체는 유효범위체인의 맨 앞에 있기 때문에 함수의 지역변수, 매개변수들과 Arguments 객체는 모두 함수 내 유효범위에 있게 된다. 이는 곧 유효범위체인의 뒤쪽에 위치한 같은 이름의 프로퍼티들은 모두 가려지게 됨을 의미한다.

네임스페이스로서의 호출객체때로는 전역 네임스페이스를 어지럽히는 대신 임시 네임스페이스로 작동할 수 있는 호출객체를 생성하여, 이 안에 원하는 변수를 정의하고 프로퍼티를 생성하기 위한 용도로 함수를 정의하는 것이 유용할 수 있다. 예를 들어 다른 여러 프로그램에 의해 코드가 사용되는 경우 한 곳에서 생성된 변수들이 이 코드를 사용하는 다른 프로그램에서 생성된 변수들과 충돌을 일으키지는 않는지 알 수가 없다는 것이 문제가 되는데, 이럴 경우 코드를 함수 안에 넣고 함수를 호출하는 것이 해답이 된다. 이 경우 변수들은 함수의 호출 객체 안에 정의된다.

function init( ) { 
    // 코드는 여기에 넣는다. 선언된 모든 변수는 전역 네임스페이스를 어지럽히는 대신 호출 객체의 프로퍼티가 된다.
}
init( ); // 그러나 함수를 호출하는 것을 잊으면 안 된다.

이 코드는 함수를 가리키는 단 한 개의 프로퍼티 init을 전역 네임스페이스에 추가한다. 만약 단 한 개의 프로퍼티를 추가하는 것도 많다고 생각된다면 익명 함수를 정의하고 호출하는 단일 표현식을 사용할 수 있다. 이를 위해 관용적으로 사용할 수 있는 자바스크립트 코드는 다음과 같다.

( function( ) { // 이 함수는 이름이 없다.
    // 코드는 여기에 넣는다.
    // 선언된 모든 변수는 전역 네임스페이스를 어지럽히는 대신 호출 객체의 프로퍼티가 된다.
} ) ( ); / 함수 리터럴을 종결하고 이를 지금 호출한다.

자바스크립트 문법에 따라서 함수 리터럴을 에워싸는 괄호가 필요함을 유의

클로저로서의 중첩된 함수

자바스크립트가 중첩된 함수를 허용하고, 함수를 데이터로 사용할 수 있고, 어휘적 유효범위를 사용한다는 것은 함께 상호작용하여 놀랍고도 매우 강력한 결과를 낸다.

함수 f안에 정의된 함수 g가 있다고 가정하자. f가 호출될 때 유효범위체인은 f호출을 위한 호출객체와 전역객체 순으로 이루어져 있다. g는 f안에 정의되기 때문에 이 유효범위체인은 함수 g 정의의 일부로서 저장된다. g가 호출될 때의 유효범위체인은 함수 g의 호출객체, 함수 f의 호출객체, 전역객체 순으로 이루어진다.

함수가 호출되면 이를 위한 호출객체가 생성되고 이 호출객체는 유뵤벙뮈체인 위에 위치한다. 함수가 종료되면 호출객체는 유효범위체인에서 제거된다. 중첩된 함수가 결부되지 않으면 유효범위체인만이 유일하게 호출객체를 가리킨다. 호출객체가 유효범위체인에서 제거되면 이에 대한 아무런 참조도 남지 않으며, 따라서 이 객체는 가비지 컬렉션에 의해 사라진다. 그러나 중첩된 함수는 이러한 상황을 변화시킨다. 중첩된 함수가 생성되면 이 함수의 정의는 호출 객체를 가리키는데, 이는 함수가 정의된 유효범위의 맨 앞에 호출객체가 존재하기 때문이다. 만약 중첩된 함수가 바깥 함수의 내부에서만 사용된다면 이 함수에 대한 유일한 참조는 호출객체 내부에만 존재한다. 바깥 함수가 반환할 때, 중첩된 함수는 호출 객체를 가리키고 호출 객체는 중첩된 함수를 가리키지만 이 둘에 대한 다른 참조들은 존재하지 않는다. 따라서 이 두 객체는 역시 가비지 컬렉션에의해 사라진다. 그러나 만약 중첩된 함수에 대한 참조를 전역 유효범위 안에 저장해 놓는다면 이야기가 달라진다. 이를 위해서는 바깥 함수의 반환값으로 중첩된 함수를 받아 사용하거나 중첩된 함수를 다른 어떤 객체의 프로퍼티로 저장해두는 수가 있다. 이 경우 중첩된 함수에 대한 외부 참조가 존재하며 이 중첩된 함수는 바깥 함수의 호출객체를 가리키는 참조를 계속 간직한다. 한 번 호출된 바깥 함수를 위하여 생성된 호출 객체는 계속하여 살아남고 함수 전달인자와 지역 변수의 이름과 값들은 이 호출 객체 안에서 계속 유지된다. 자바스크립트 코드는 호출 객체에 직접적으로 접근할 방법이 없다. 그러나 정의된 프로퍼티들은 중첩된 함수 호출을 위한 유효범위체인의 일부가 된다.

자바스크립트 함수는 실행될 코드와 이 함수가 실행될 유효범위의 조합이다. 컴퓨터 과학 문헌에서 이러한 코드와 유효범위의 조합은 클로저(closure)로 알려져있다. 모든 자바스크립트 함수는 클로저다. 이 클로저가 유일하게 흥미로운 경우는 중첩된 함수가 그 함수가 정의된 유효범위 바깥으로 익스포트(export)될 때다.

클로저의 예

함수 호출의 경계를 넘어 그 값을 기억할 수 있는 함수를 작성하고 싶을 때가 종종 있다. 호출 객체는 함수 호출의 경계를 넘어 존재를 유지할 수 없기 때문에 이 값은 지역 변수 안에 저장할 수가 없다. 전역 변수를 사용할 수는 있지만 이는 곧 전역 네임스페이스를 오염시키게 된다. –전역 네임스페이스를 오염시킨다는 것은 전역 변수로 설정할 경우 협업시 문제가 발생할 수가 있다는 것– 앞서 소개한 uniqueInteger( ) 함수는 사라지지 않는 값을 저장하기 위한 용도로 함수 자신의 프로퍼티를 사용했었는데, 클로저를 사용하면 여기서 한 발짝 더 나아가 사리지지 않으면서도 private 속성을 지니는 변수를 생성할 수 있다.

예 1)

uniqueID = ( function( ) { 
    // 이 함수의 호출 객체가 우리의 값을 저장한다. 
    var id = 0; 
    // 이것이 바로 지속성 있으면서도 private 속성을 지닌 값이다. 
    // 바깥 함수는 중첩된 함수를 반환하는데, 이 중첩된 함수는 위의 지속성 있는 값에 접근할 수 있다. 
    // 위의 uniqueID 변수에 저장되는 것은 이 중첩된 함수이다. 
    return function( ) { return id++; }; // 값을 증가시켜서 반환한다. 
} ) ( ); // 바깥 함수를 정의하고 호출한다.

예 2)

// 이 함수는 객체 o가 가진 name이란 이름의 프로퍼티에 접근하기 위한 메서드를 추가한다. 
// 메서드의 이름은 get과 set이다. 
// 만약 술어 함수가 함께 제공되면 setter(값을 설정하는) 메서드는 값을 설정하기에 앞서서 값이 적법한지를 판단하기 위해 술어 함수를 사용한다. 
// 만약 이 함수가 false를 반환하면 setter 메서드는 예외를 발생시킨다. 
// 이 함수의 별난 특징은 getter(값을 읽어오는) 메서드와 setter(값을 저장하는) 메서드에 의해 조작되는 프로퍼티 값이 객체 o에 저장되어 있지 않다는 점이다. 
// 대신에 이 값은 함수의 지역 변수로만 저장된다. 
// getter와 setter 메서드들도 또한 함수에 지역적으로 정의되어 지역 변수에 접근할 수 있다. 
// 따라서 이 값은 getter와 setter 메서드에 의해서만 접근할 수 있으며, 오직 setter 메서드에 의해서만 설정되거나 변경될 수 있다. 
function makeProperty(o, name, predicate) { var value; } // 이것이 프로퍼티 값이 된다.

// getter 메서드는 단순히 값을 반환하는 역할을 한다.
o["get" + name] = function( ) { return value; };


// setter 메서드는 값을 저장하는 역할을 하는데, 만약 predicate가 값을 거부하면 예외를 발생시킨다.
o["set" + name] = function(v) {
    if ( predicate && !predicate(v) )
        throw "set" + name + ": invalid value " + v;
        else
        value = v;
    };
}


// 다음의 코드는 makeProperty( ) 메서드를 시험한다.
var o = { }; // 여기에 빈 객체가 있다.


// getName과 setName이란 이름의 프로퍼티 접근 메서드들을 추가한다.
// 오직 문자열 값만 허용되도록 보증한다.
makeProperty(o, "name", function(x) { return typeof x == "string"; } );


o.setName("Frank"); // 프로퍼티 값을 설정한다.
print( o.getName( ) ); // 프로퍼티 값을 읽어온다.
o.setName(0); // 잘못된 데이터 타입의 값을 설정하려고 시도한다.

예 3) 중단점 중단점이란 함수 내의 한 지점을 말하는데, 이 위치에서 함수는 실행을 멈추고 프로그래머에게 변수의 값을 조사하거나 표현식을 평가하고 함수를 호출하는 등의 작업을 수행할 수 있는 기회를 제공한다. 스티브 옌(Steve Yen)의 중단점 기술은 클로저를 사용하여 함수 안의 현재 유효 범위를 포착하고 이를 저역 함수인 eval( )과 함께 사용함으로써, 포착한 유효 범위 한의 값을 조사할 수 있게 한다. eval( )은 자바스크립트 코드를 담은 문자열을 평가하고 그 값을 반환한다. 다음 코드의 중첩된 함수는 자기 조사(self-inspecting)가 가능한 클로저로 작동한다.

// 현재의 유효범위를 포착하고 이를 eval( )을 사용하여 조사할 수 있게 한다.
var inspector = function($) { return eval($); }

클로저와 IE의 메모리 누수 현상

MS의 IE 웹브라우저가 사용하는 가비지 컬렉션 기법은 ActiveX 객체와 클라이언트 측 DOM 엘리먼트에 대해 취약하다. 이 클라이언트 측 객체들에 대한 참조의 개수를 세고 있다가 참조 수가 0이 되는 순간 객체를 메모리 상에서 제거하는 방식을 사용하는데, 이 방식은 순환 형태의 참조가 존재할 경우 실패한다.

IE 상의 클라이언트 측 프로그래밍에서 클로저가 사용될 때에는 이런 종류의 순환 형태 참조가 자주 발생한다. 클로저를 사용할 때는 함수의 모든 전달인자와 지역 변수를 포함하는 바깥 함수의 호출 객체가, 클로저가 존재하는 한 메모리상에서 사라지지 않음을 기억하라. 만약 이러한 함수 전달인자나 지역 변수가 클라이언트 측 객체를 참조한다면 이는 곧 메모리 누수 현상을 일으킨다.

Function( ) 생성자

함수는 Function( ) 생성자를 사용해서도 정의될 수 있다. Function( ) 생성자를 사용하는 것은 보통 함수 리터럴을 사용하는 것보다 난해하기 때문에 이러한 테크닉은 그리 널리 쓰이지는 않는다.

var f = new Function( "x", "y", "return x*y;" );
It's only fair to share...Share on FacebookShare on Google+Tweet about this on TwitterShare on LinkedIn

The author

지성을 추구하는 디자이너/ suyeongpark@abyne.com

댓글 남기기