함수의 정의

함수는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행단위로 정의한 것이다.

함수 리터럴도 평가되어 값을 생성하며, 이 값은 객체다. 즉, 자바스크립트 함수는 일급 객체다. 일반 객체는 호출할 수 없지만, 함수는 호출할 수 있다는 차이가 있다.

→ 자세한건 19장 프로토타입에서 알 수 있다.

일급 객체는 변수에 할당할 수도 있고, 프로퍼티 값이 될 수도 있으며, 배열의 요소가 될 수도 있는 것처럼 값의 성질을 갖는 객체를 의미한다.

함수 생성법

  1. 함수 선언문

    function add(x,y) {
    	return x + y;
    }
    
  2. 함수 표현식

    var f = function add(x,y) {
    	return x + y;
    }
    
  3. Function 생성자 함수

    var add = new Function('x', 'y', 'return x+y');
    

    바람직한 사용은 아니므로 어지간하면 쓰지 말자.

  4. 화살표 함수

    var add = (x, y) => x + y;
    

    항상 익명함수이며, prototype 프로퍼티가 없고, this 바인딩 방식이 다르고, arguments 객체를 생성하지 않는다.

함수 리터럴

var f = function add(x,y) {
	return x + y;
}

위 코드에서 f는 함수가 할당된 변수, add는 함수 이름이다.

함수 이름은 함수 몸체 내에서만 참조할 수 있는 식별자다.

함수 이름은 생략할 수 있고, 이름이 있으면 기명함수, 없으면 익명함수라고 한다.

// 기명 함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석된다.
// 함수 선언문에서는 함수 이름을 생략할 수 없다.
function foo() { console.log('foo'); }
foo(); // foo

// 함수 리터럴을 피연산자로 사용하면 함수 선언문이 아니라, 함수 리터럴 표현식으로 해석된다.
// 함수 리터럴에서는 함수 이름을 생략할 수 없다.
(function bar() { console.log('bar'); });
bar(); // ReferenceError : bar is not definded

위에 bar는 함수 객체를 생성한다는 점에서 foo와 동일하지만, 함수 리터럴 표현식으로 생성된 bar는 호출할 수 없다.

함수 몸체 외부에서는 함수 이름으로 함수를 참조할 수 없으므로, 함수 몸체 외부에서는 함수 이름으로 함수를 호출할 수 없다. 즉, 함수를 가리키는 식별자가 없는 것과 마찬가지다. 따라서 위 예제의 bar 함수는 호출할 수 없다.

하지만 함수 선언문으로 정의된 foo는 몸체 외부에서 호출할 수 있었다. 이는 JS 엔진이 암묵적으로 생성한 식별자다.

image.png

image.png

JS 엔진은 함수 선언문을 해석해 함수 객체를 생성한다. 이때 함수 이름은 함수 몸체 내부에서만 유효한 식별자이므로, 함수 이름과는 별도로 생성된 함수 객체를 가리키는 식별자를 생성한다. 그리고 거기에 함수 객체를 할당한다.

// 기명 함수 표현식
var add = function foo (x, y) {
    return x + y;
};

// 함수 객체를 가리키는 식별자로 호출
console.log(add(2, 5)); // 7

// 함수 이름으로 호출하면 ReferenceError가 발생한다.
// 함수 이름은 함수 몸체 내부에서만 유효한 식별자다.
console.log(foo(2, 5)); // ReferenceError: foo is not defined