자바스크립트의 함수

함수란?

함수

자바스크립트에서 가장 중요한 것이 무엇이냐고 했을 때 십중팔구는 함수를 이야기 할 것이다. 자바스크립트의 함수는 모듈화, 클로져, 객체 생성, 함수형 프로그래밍 지향에 있어서 정말 중요한 개념이고 잘 이해하여야 한다.(그런 의미에서 나는 아직 멀었다.)

함수의 생성방법

함수 생성방법은 객체 생성방법과 비슷하게 3가지가 있다. 함수 선언문, 함수 표현식, Function() 생성자 함수 이 세가지 이다.

  • 함수 리터럴

계속 강조하지만 함수도 결국 객체이다.(일급 객체라서 중요하다!) 그렇기 때문에 함수 리터럴 방식이 존재한다.

function multiply(x,y) {
  return x * y;
}

함수 키워드, 함수 명, 매개변수 리스트로 구성되어 있다.

  • 함수 선언문

함수 리터럴과 형태는 같지만 주의할 점은 반드시 함수명이 있어야 한다는 점이다.

function multiply(x,y) {
  return x * y;
}

console.log(multiply(3,4));

출력결과

12

  • 함수 표현식

함수 표현식은 함수 리터럴로 함수를 생성하여 생성된 함수를 변수에 할당하는 형태이다.

var mul = function (x,y) {
  return x * y;
}

console.log(mul(3,4));

출력결과

12

이렇게 이름이 없는 함수 형태를 익명함수라고 부른다. 즉 변수 mul을 통해 함수를 할당한 것을 익명 함수를 이용한 함수 표현식이라고 한다.
위 예제는 기명 함수 표현식으로도 가능하다. 다만 함수 표현식에서 사용된 함수 이름은 외부 코드에서의 참조가 불가능하다.

이를 활용해서 팩토리얼 함수를 만들어 보도록 하자.

var factorial = function factorial(n) {
  if ( n <= 1) { return 1; }
  return n * factorial(n-1);
}

console.log(factorial(3));
console.log(factorial(1));

출력결과

6
1

이는 재귀 호출을 이용한 방법으로 함수를 선언한 후 함수 내부에서 재귀호출하여 함수를 처리하였다.

  • Function() 생성자 함수

자바스크립트의 함수도 결국 Function()이라는 내장 생성 함수에서 생성된 것이다. (축약 표현일 뿐이다.)

var add = new Function('x', 'y', 'return x + y');
console.log(add(3,4));

출력결과

7

함수 호이스팅

자바스크립트의 권위자 인 더글라스 크락포드는 함수 생성에서 함수 표현식만을 사용할 것을 권하고 있는 데 그 이유가 바로 호이스팅 때문이다.

// 함수 호이스팅으로 인한 호출 가능.
var res = square(5);

function square(number) {
  return number * number;
}


// TypeError
var res = square(5);

var square = function(number) {
  return number * number;
}

함수 표현식은 변수 호이스팅이 발생하기 때문에 함수 호이스팅 처럼 변수생성, 초기화, 할당이 한 번에 일어나는 것이 아니라 변수 호이스팅 처럼 생성과 초기화만 동시에 일어난다.
결론적으로 함수 호출 전에는 반드시 함수를 선언하여야 한다.

함수 = 객체

자바스크립트의 함수는 결국 객체이기 떄문에 일반 객체처럼 프로퍼티들을 가질 수 있다. 그렇기 때문에 위에서 설명한 것처럼 리터럴에 의한 생성, 변수나 배열 요소, 객체 프로퍼티 할당 가능, 함수의 인자로 전달 가능, 함수의 리털값으로 사용 가능, 동적으로 프로퍼티 생성 및 할당 가능 등 객체와 똑같이 적용된다.

위에 나열한 기능이 모두 가능하기 때문에 함수를 일급 객체라고 부르는 것이다.

  • 변수나 프로퍼티에 할당.

함수도 변수나 프로퍼티에 할당할 수 있다.

var foo = 100;
var bar = function() { return 100; };
console.log(bar());

var obj = {};
obj.baz = function () { return 200; };
console.log(obj.baz());

출력결과

100
200

  • 함수 인자로 전달.

다른 함수의 인자로 전달 가능하다.

var foo = function(func) {
  func();
};

foo(function() {
  console.log('kkk');
});

출력결과

kkk

  • 리턴값으로 활용

다른 함수의 리턴값으로도 활용할 수 있다.

var a = function() {
  return function() {
    console.log('apple')
  };
};

var b = a();
b();

출력결과

apple

변수 b에 함수 a를 호출하면 리턴값으로 전달되는 함수가 b 변수에 저장되어 apple이 출력된다.

  • 기본 프로퍼티

정말 중요하다. 함수는 객체다. (일급객체) 또한 함수 객체만의 프로퍼티를 가지고 있다. 크롬 검사도구에서 함수를 살펴보면 arguments,caller, length 등과 같은 프로퍼티가 보인다는 것을 알 수 있다. (console.dir로 호출해 보시길)
또한 객체이기 때문에 prototype을 갖는다. 함수 객체의 프로토타입은 Function.prototype 객체이다.

  • prototype과 [[prototype]]

이 둘은 많이 헷갈릴 수 있는 개념이다. 하지만 둘은 엄연히 다른 개념이다. 물론 두 프로퍼티가 모두 프로토타입 객체를 가리킨다. 하지만 보는 관점에서 차이가 있다.

  1. [[prototype]]
    객체 입장에서 자신의 부모 역할을 수행하는 프로토타입 객체를 가리킨다.

  2. prototype
    함수가 생성자일 때 함수를 통해 생성된 객체의 부모 역할을 하는 개체를 가리킨다. 그래서 함수를 생성할 때 만들어지고 constructor 프로퍼티 하나만 있는 객체를 말한다.

프로토타입

함수 형태

  • 콜백 함수
    익명 함수가 사용되는 대표적인 용도가 콜백함수이다. 콜백 함수는 어떤 이벤트가 발생했을 때 시스템에서 호출되는 함수이다.
    대표적인 예로 이벤트 핸들러 처리가 있다.
  • 즉시 실행 함수
    Immediate function은 정의와 동시에 출력되는 함수이다.

    (function (name) {

    console.log('welcome -> ' + name);
    

    })(‘Jang’);

출력결과

welcome -> Jang

즉시시행함수는 바로 시행되지만 다시 호출할 수 없기 때문에 한 번만 실행하는 초기화 실행 같은 코드에 적합하다.
(추후에 즉시실행함수에 대해 한 번 다뤄보도록 하겠습니다.)

  • 내부 함수
    자바스크립트 함수는 내부에서도 함수를 정의할 수 있다. 이를 내부함수라고 한다.

    function parent() {

    var a = 100;
    var b = 200;
    
    function child() {
      var b = 300;
    
      console.log(a);
      console.log(b);
    }
    child();
    

    }
    parent();
    child();

출력결과

100
300
ReferenceError: child is not defined

100이 출력되는 이유는 스코프 체이닝에 의해서 child함수의 부모인 parent 함수에서 변수 a의 값을 찾았기 때문에 가능한 것이다.
또한 내부 함수는 자신을 둘러싼 외부 함수에서 접근이 가능하지만 그 내부에서만 호출이 가능하기 때문에 레퍼런스 에러가 발생했다.