2015년 2월 23일 월요일

[JavaScript] 자바스크립트의 Function(함수)

타 프로그래밍 언어와 같이 자바스크립트(ECMAScript)의 함수(Function)는 Statement들을 언제 어디서든 실행할 수 있게 그 Statement들을 캡슐화(Encapsulation)하기 때문에 매우 중요한 기능을 하는 요소 중 하나 이다. 참고로 Function도 자바스크립트의 Object(객체) 자료형에 포함된다.
즉, 자바스크립트의 모든 함수(Function)들은 Object(객체)의 하위 개체인 Function 타입에 속하고, 우리가 프로그래밍시 함수(Function)에 부여하는 함수 이름은 다른 reference type의 경우처럼, 메모리에 저장된 함수 객체를 가리킬 뿐이다. 그렇기 때문에 함수(Function)은 일반 변수처럼(function expression) 선언이 가능하며, 코드상에 이름이 같은 함수 2개가 존재해도 Exception이 발생하지 않으며, 객체(Object)가 자신 내부에 또 다른 객체(Object)를 저장하는 것 처럼, 함수(Function)안에도 또 다른 함수를 선언할 수 있고, 하나의 함수를 여러가지 변수로 호출 할 수도 있다.

  • 참고로 Strict Mode에서 함수 선언시 함수 이름이나 함수 파라미터에 "eval" 또는 "arguments"라는 단어를 쓰지 못한다, 이는 좀 이따가 다루도록 하겠다
  • 자바스크립트(ECMAScript)에서 함수로 전달되는 Arguments는 언제나 Pass By Value이다. 즉 함수에서 전달된 Argument의 값을 변경해도 원래의 Argument 변수에는 영향이 가지 않는다.

함수(Function)의 선언


함수(Function)는 아래와 같이 정의가 가능하다.
정확히 말하자면 함수 정의는 2가지 방법으로 가능하다.
Function Declaration(함수 선언)Function Expression(함수 표현).
이 두가지 방법의 차이에 대해서는 다른 글(클릭하기)에서 좀 더 자세히 다뤄보도록 하겠다.


// Function Declaration
function functionIdentifier(arg1, arg2, arg3){
console.log("Demo Function Argument 1" + arg1);
console.log("Demo Function Argument 2" + arg2);
console.log("Demo Function Argument 3" + arg3);
// Statement를 여기에 적으면 된다.
}
// functionIdentifier 자리에는 함수의 이름이 오게되고
// 그 옆의 괄호안에는 함수 파라미터(Formal Parameter)가 오면 된다.

// 또는 아래와 같이 var 키워드를 이용 할 수도 있다. -Function Expression
// 알아야 할것은, 함수 표현식에서 정의되는 함수들 중, 
// function identifier가 정의되지 않은 함수들은
// 모두 anonymous function 또는 lambda function으로 불리며, 
// 이런 함수들은 이름(Function Identifier)를 가지지 않는다.
// 이 때문에 함수 객체의 "name" 프로퍼티는 공백의 문자열(empty string)이 된다.
// 즉, 해당 변수가 정의된 함수 객체를 참조할 뿐인것이다.
var functionExpressionExample1 = function functionIdentifier(arg1,arg2){
console.log("This is Function Expression1");
};

var functionExpressionExample2 = function(arg1,arg2){
console.log("This is Function Expression2");
};

// Self executing function이라 불리는 기법
// 함수 호출이 없이 함수가 실행된다.
(function(arg1,arg2){
console.log("This is Self executing function");
})();

//여러 변수들이 한개의 함수를 가리키게 할 수도 있다.
var func0 = functionName(arg1, arg2, arg3);
var func1 = functionName(arg1, arg2, arg3);
var func2 = functionExpressionExample1;


함수(Function)의 호출


함수(Function)은 언제 어디서든 함수 이름과, 아규먼트(Argument)를 괄호()에 포함해 호출이 가능하다.

//파라미터로 주어진 두 변수의 합(두 변수가 숫자일 경우), 또는 문자열의 합을 반환하는 함수
function addition(arg1, arg2){
return arg1 + arg2;
}

console.log(addition(3,4));//7


타 프로그래밍 언어와 달리, ECMAScript 함수는 주어지는 Argument의 갯수가 Formal Parameter의 갯수와 일치하지 않아도 함수 호출이 가능하다. 말인즉, 이름이 같은 함수 A가 Formal Parameter로 2개의 변수를 받을 때, 3개 또는 0개의 Argument로도 함수 A를 호출 할 수 있다는 뜻 이다. 이는 자바스크립트가 함수(Function)에 Argument 를 전달할 때 Array 객체로 전달하기 때문이다. 다른 프로그래밍 언어(특히 Java)와는 궤를 달리하는 방식인데, 이러한 이유 때문에, Java 또는 C#에서 가능한 method polymorphism이 Javascript(ECMAScript)에서는 구현이 불가능 하다.
참고로 Argument 값이 주어지지 않는 Parameter는 언제나 Undefined 값을 가지게 된다.


//파라미터로 주어진 두 변수의 합(두 변수가 숫자일 경우), 또는다 문자열의 합을 반환하는 함수
function addition(arg1, arg2){
return arg1 + arg2;
}

console.log(addition(3,4));//7
console.log(addition(3));//NaN 이 경우에는 arg2에 undefined 값이 어싸인 된다.
console.log(addition(3,4,6));//7 이 경우에는 세번째 아규먼트는 사용되지 않는다.


이게 가능한 이유는 Array(배열)형식으로 전달된 Arguments들과, 함수의 실행시 전달된 Argument Array의 사이즈를 확인하지 않는 자바스크립트(ECMAScript)의 특성 때문이다. 이러한 특수한 이유 때문에 자바스크립트(ECMAScript)의 함수에서 배열에 접근하듯 Array Bracket Notation([] 사각 괄호안에 인덱스를 넣어 배열에 접근하는 방법)을 이용해서 함수에 주어진 Argument에 접근할 수 있다.
  • 참고로 배열의 이름은 "Arguments" 이다, 이 때문에 Strict 모드에서 "Arguments"라는 단어를 함수 이름이나 함수 파라미터의 이름으로 사용할 수가 없다.


//파라미터로 주어진 두 변수의 합(두 변수가 숫자일 경우), 또는 문자열의 합을 반환하는 함수
function addition(arg1, arg2) {
 if (arguments[2] == undefined) {
  return arg1 + arg2;
 } else {
  return arg1 + arg2 + arguments[2]
 }
}
console.log(addition(3,4));//7
console.log(addition(3));//NaN
console.log(addition(3,4,6));// 13


위의 코드에서 arg1, arg2는 각각 arguments 배열의 인덱스 0과 1에 위치하고, 3번째 Argument는 인덱스 2에 위치하게 된다.
그렇기 때문에 3번째 Argument, 즉 인덱스 2에 위치한 변수가 undefined 값을 가진 경우에는 첫번째 두번째 변수의 합을 반환하지만, 반대의 경우에는 주어진 3개의 변수들 모두의 합을 반환하게 된다. 또는 아래와 같은 사용도 가능하다.


function demoConcatString() {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t;
}

console.log(demoConcatString("This", "is", "demo"))// This is demo;


함수의 Arguments 배열은 매게 변수들을 제외하고도 callee 라는 프로퍼티를 가지고 있는데, Arguments 배열과 관계된 함수를 가리킨다.


function demo() {
    console.log(arguments.callee);
}

demo();// [Function: demo]


arguments.callee 가 호출 된 함수를 가리킨다면, function.caller 는 호출 한 함수를 가리킨다. 만약 global context에서 호출됬다면 null 값을 가진다.


function demo() {
    console.log(demo.caller);
}

function caller() {
    demo();
}

demo();// null, global 컨텍스트에서 호출 됬을 때는 null

caller();// [Function: caller]


함수 오버로딩(Function Overloading)


위에서 잠깐 이야기 했듯, 자바스크립트의 함수는 객체에 불과하며 Arguments 들이 배열(Array) 형식으로 전달되기 때문에 사실상 Function Signature를 가지지 않는다. 이러한 이유 때문에 자바(Java)나 C# 등에서 사용되는 Method Overloading은 구현이 불가능하다. 만약 같은 이름의 함수를 여러개 선언했다면, 가장 마지막에 선언된 함수가 실행될 것이니 이러한 실수는 피하도록 하자.


function demoConcatString(arg1) {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t + "1";
}
function demoConcatString(arg1, arg2) {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t + "2";
}
function demoConcatString(arg1, arg2, arg3) {
    var t = "";
    for (var i = 0; i < arguments.length; i++) {
 t = t + arguments[i] + " ";
    }
    return t + "3";
}

console.log(demoConcatString("This", "is", "demo")); //This is demo 3, 가장 마지막의 함수가 호출된다.

댓글 없음:

댓글 쓰기