함수 선언문과 함수 리터럴은 형태가 동일하다. 그러면 자바스크립트는 어떻게 해석하는가?
문맥에 따라 함수 선언문이여야 하는지, 함수 리터럴이여야 하는지를 판단한다.
아래 예제를 보자.
// 함수 리터럴
var add = function add(x, y) {
return x + y;
}
// 함수 호출
console.log(add(2, 5)); // 7
위에서 function add를 함수 선언문이라고 가정하면, 할당 연산자에 의해서 변수에 값이 할당될 수 있어야 한다.
즉 함수 선언문은 값으로 평가될 수 있어야 한다. 하지만 함수 선언문은 표현식이 아닌 문, 즉 값으로 평가될 수 없으므로
해당 자리에는 함수 선언문이 올 수 없다.
따라서 값으로 평가될 수 있는 함수 리터럴이 와야하는 자리이므로, 자바스크립트는 function add를 함수 표현식으로 해석한다.
// 함수 선언문
function foo() {
console.log("foo");
}
foo();
// 함수 리터럴
(function bar() {
console.log("bar");
});
bar(); // ReferenceError: bar is not defined
단독으로 사용되었으므로 함수 선언문으로 해석된다.
함수 이름으로는 함수 외부에서 함수를 참조할 수 없다.
함수 선언문의 경우엔 함수 객체를 가리키는 식별자를 함수가 포함된 스코프에 암묵적으로 생성한다.
즉 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 암묵적으로 생성하고, 거기에 함수 객체를 할당한다.
따라서 함수 선언문으로 생성된 foo는 호출할 수 있다.
그룹 연산자 ()의 피연산자는 값으로 평가될 수 있는 표현식이여야한다. 따라서 함수 리터럴 표현식으로 해석된다.
함수 이름으로는 함수 외부에서 함수를 참조할 수 없다.
함수 리터럴로 생성된 함수는 함수를 가리키는 식별자가 없으므로 bar함수는 호출할 수 없다.
함수는 함수 이름으로 호출하는 것이 아니라, 함수 객체를 가리키는 식별자로 호출한다.
따라서 아래와 같이 함수 리터럴에 식별자를 붙여주면 함수 외부에서 함수 호출이 가능해진다.
// f: 식별자, add: 함수 이름
var f = function add(x, y) {
return x + y;
};
// 식별자로 함수를 호출한다
console.log(f(2, 5)); // 7
console.log(add(2, 5)); // ReferenceError: add is not defined