2012년 9월 6일 목요일

Javascript의 Function의 속성 및 메서드

# 개요  

자바스크립트에서 제일 중요한 요소는 함수입니다.
흔히 일급 객체 (first-class-object) 라고 불리는 자바스크립트 함수는 자바스크립트에서 거의 모든 것을 할 수 있습니다. 보통 언어에서 흔히 지원되는 함수의 동작인 실행, 값의 반환같은것은 당연하게 수행하며, 자신이 반환값이 되기도 하고 인자로서 넘겨지기도 하며, 객체의 프로퍼티나 변수 할당도 가능합니다.

심지어 변수 스코프 경계를 짓거나, new 연산자와 쓰여 다른 객체를 생성하는 생성자 역할 및 클로저로서도 동작하는 그야말로 만능 엔터테이너입니다.

그리고 많은 분들이 재미있어(?) 하시는 prototype 속성을 가진 객체이기도 합니다.

함수는 어떤 속성과 메서드를 갖는지 한번 알아봅시다. 


함수의 속성들 

자바스크립트에서는 함수도 엄연한 Object이기에 속성을 가지고 프로그래머가 임의로 정의할 수도 있습니다. 또한 기본으로 여러 속성을 가지고 있기도 합니다.

그런 것들은 대부분 Function이라는 빌트인 함수의 프로토타입에서 상속된 것입니다.

arguments
함수가 실행될 때 바인딩되는 늦은 바인딩 변수입니다.
함수가 생성되었을 당시에는 null 값을 가지고 있습니다. 런타임이 굉장히 중요한 함수죠.

유사 배열 객체(array-like object)로서 함수가 실행되었을 때 전달되어 초기화된 인자를 순서대로 0번 인덱스부터 첨자로 하여 배열 형식으로 가지고 있습니다. 
function javarouka() {
    // 인자를 따로 선언하지 않아도 런타임시 주어진 인자로 초기화됩니다.
    // 그리고 배열과 같은 기능을 하는 속성 length가 있습니다.
    for(var i=0; i < arguments.length; i++) {
        console.log(i + "째 인자의 값은 " + arguments[i]);
    }
    // false. 배열이 아닙니다.
    console.log (arguments instanceof Array)               
}
console.log(javarouka.arguments) // 실행 전에는 null 입니다.
javarouka("hello", "javascript", "function", "property!"); // 잘 출력되겠죠?
절대 배열로 착각하여 arguments.push() 나 arguments.slice() 같은 배열 메서드를 사용하지 마세요. 만일 사용하고 싶다면
Array.prototype.push.call(arguments, "밀어넣을 요소");
var aryArgs = Array.prototype.slice.call(arguments); // 진짜 인자 배열 얻기
형식으로 배열의 함수를 컨텍스트만 자신으로 바꿔서 사용하면 됩니다.
또한 실행중인 자기 자신을 참조하는 callee 속성도 눈여겨 볼만 합니다. 
var i = 0;
(function() {
    if(i < 10) {
        document.writeln(i++);
        // arguments.callee은 자기 자신을 참조하는 속성입니다.
        setTimeout(arguments.callee, 100);
    }
})();
// 0123456789 가 출력될 겁니다
혹자는 이 arguments 속성이 자바스크립트에서 함수 호출의 유연함을 강조한다고 하지만 개인적으로는 혼돈에 빠뜨리는 속성이라고 생각합니다.
MDN에서는 이 속성을 Deprecated 로 정의하고 있지만, 기존 소스에서 사용되는 빈도가 높아 없어지진 않을 것 같습니다.

length
함수 생성시 지정한 받을 인자의 개수를 나타냅니다.
대다수의 브라우저에서 지원합니다. 하지만 경험상 막상 쓸일이 그리 없었던 듯 합니다. 
function nonblock(val1, val2) {
    /* 뭔가 열심히 하는 로직 */
}
console.log(nonblock.length) // 2
주의할 점이 있는데, arguments.length의 값과는 다를 수 있습니다.
이쪽은 선언적인 인자의 숫자이며, arguments.length는 실행시 인자의 숫자입니다.

constructor
Object에서 상속받은 속성입니다. 자신을 생성한 함수를 가르킵니다.
일반적으로 콘솔이나 alert등으로 출력을 시도할 경우 네이티브 함수의 toString() 값인 function Function() { [native code] } 을 볼 수 있을 것입니다.
실제 반환되는건 Function 객체입니다. 
function Niceguy() {
    /* ...이런저런 구현... */
}
// Niceguy 라는 함수객체는 네이티브코드에서 생성됩니다
console.log(Niceguy instanceof Function) // true.
console.log(Niceguy.constructor) // function Function() { [native code] }

// 반면, 생성자로 쓰일 경우 생성된 객체의 constructor가 됩니다.
var javarouka = new Niceguy();
console.log(javarouka.constructor) // Niceguy
caller
자신을 실행시킨 함수를 반환하는 비표준 속성입니다.
만일 속성값이 null이라면 글로벌 컨텍스트에서 실행한 것입니다.

다음 예제를 보세요. 
var obj = {
    a: function() {
        return obj.a.caller;
    },
    b: function(f) {
        return f();
    }
}
obj.a(); // null
obj.b(obj.a); // obj.b 반환. toString()은 function (f) { return f(); } 가 됩니다.
name
함수의 이름을 반환하지만 이 경우 반드시 함수 선언문으로 한 경우에만 반환됩니다.
비표준이며, IE는 지원하지 않습니다.

(2012-02-17 추가) 

함수 선언문 뿐 아니라 이름을 가진 함수 리터럴(named function-literal) 일 경우에도 name 속성이 나오는군요. 이때 함수가 할당된 변수가 name이 되는게 아닌 함수 리터럴에 지정한 이름이 name이 됩니다. 
// 함수 선언문
function func1() { /* ... */ }
func1.name // "func1"

// 함수 표현식 변수할당
var func2 = function() { /* ... */ }
func2.name // "" ( or undefined or null? )

// 이름을 가진 함수 표현식
var func3 = function myFunc() { /* ... */ }
func3.name // "myFunc"

prototype
함수(내장함수도 물론 포함합니다)만이 가지고 있는 속성으로 자바스크립트 객체지향의 근간입니다. 이것만 왜 붉은 색이냐 하면 그만큼 중요하기 때문입니다.

설명은 기존의 포스트를 참고해 주세요
http://blog.javarouka.me/2011/12/prototype-property-and-prototype-chain.html 


함수의 메서드들

함수도 객체이기에 메서드들을 가질 수 있습니다.
보통 함수에 사용자가 뭔가를 정의할일은 거의 없습니다. 라이브러리 레벨의 범용성을 추가할 때 사용되는게 대부분입니다.

아래 소개할 함수 대부분도 call이나 apply등을 빼면, 고급 기능에서나 사용될 법 한 것들입니다.

apply(컨텍스트 [, 인자의 배열 ])
call(컨텍스트 [, 인자1, 인자2....])
기능이 같으므로 함께 설명합니다.
이 메서드를 사용하면 함수를 실행시키는 컨텍스트를 직접 지정할 수 있습니다. 쉽게 말하면 this변수에 연결될 객체를 선택할 수 있습니다.

apply, call 둘다 첫번째 인자는 활성 객체이며 두번째 인자부터만 다릅니다.
apply는 함수를 실행할 인자를 배열 형식으로 절달하며, call은 인자를 하나하나 나열하는 식이죠.
첫번째 컨텍스트를 전달하지 않거나 null을 주게 되면 글로벌 컨텍스트로 지정됩니다.

다음의 예제를 보세요. 
function Computer(name, price) {    
    this.name = name;
    this.price = price;  
}
function Notebook(name, price) {
    // 호출 객체를 현재 생성될 객체로 지정합니다.
    Computer.apply(this, arguments);
    this.type = "portable";
}

var vaio = new Notebook("VAIO", 2250000);

vaio.name // "VAIO"
vaio.price // 2250000
vaio.type // "portable"
위의 Notebook 함수를 생성자로 써서 만든 객체 vaio는 생성자에서 Computer를 호출함으로써 name과 price를 자신의 속성으로 지정할 수 있지요.

보통은 저런 용도로 쓰진 않지만요...

bind(컨텍스트 [, 인자1, 인자2....])
위의 call, apply와 비슷하지만 이번에는 주체가 함수가 됩니다.
함수의 스코프 체인과 프로토타입을 첫번째 인자의 것으로 모두 바꾸고 나머지 인자를 함수에 전달하여 실행합니다.

말로 하니 복잡한데 예제를 봅시다. 
var name = "Lee";
var other = {
    name: "Kim"
}
function getName() {
    return this.name;
}
getName() // 전역 참조. 결과는 "Lee"

var wasBound = getName.bind(other);
wasBound(); // 바인드 된 객체 참조. 결과는 "Kim"
함수를 특정 객체의 스코프 체인에 묶어버리는(bind) 기능입니다.
아직은 크롬과 파이어폭스에서만 지원됩니다.

toString
Object에서 상속한 메서드로서 본래 기능은 해당 값의 문자열 형식을 반환하게 되어 있습니다. 대부분의 자바스크립트 엔진 구현에서는 함수의 toString을 호출하면 함수 소스코드의 내용이 나옵니다. 네이티브 코드로 구현된 부분은 소스코드의 내용이 공개되지 않습니다.

문자열 결합 연산자 (+) 나 alert, document.write() 등의 인자가 되거나 해서 문자열이 필요한 경우 자동으로 호출되어 연산됩니다. 
function javarouka() {
    /* 뭔가 한다 */
}
// toString을 override
javarouka.toString = function() {
    return "Happty Programer";
}
// 문맥상 문자열 연산이 필요할 때 자동으로 호출됩니다
console.log("블로그의 주인은 " + javarouka + "입니다");
valueOf
역시 Object에서 상속된 메서드로서 값의 원시값(primitive value) 값을 반환하게 되어 있습니다. 역시 대부분의 엔진에서는 함수 자체를 그대로 반환합니다.
-, /, * 등의 산술 연산에 함수를 직접 쓸 경우 자동으로 호출됩니다.

혹시라도 함수로 숫자 연산을 하고 싶다면 오버라이딩 해 두면 덧셈뺄셈등의 연산이 가능해 집니다. (그런데 그럴 일이 있을지 모르겠습니다) 
function one(i18n) {
    if(i18n === "ko") return "하나";
    else if(i18n === "jp") return "いち";
    return "one";
}
one.valueOf = function () { return 1; }

// 원시 값 연산이 필요한 경우 자동으로 호출됩니다.
var result = 38 - one;
console.log(result) // 37
toSource
함수의 소스코드를 문자열로 반환합니다. 대부분의 경우 toString과 결과가 같습니다.




------------------------------------------------------
출처 - http://blog.javarouka.me/2012/02/javascript-function.html

댓글 없음:

댓글 쓰기

블로그 보관함