JS-함수2
함수 선언문과 함수 리터럴 표현식이든 함수가 생성되는 것은 동일하지만 생성되는 내부 방식은 다르다.
function foo (){
console.log('foo');
}
//함수 선언문
foo(); // foo
//함수 리터럴을 피연산자로 사용하면 or 함수 리터럴을 변수에 할당하는 경우
//함수 선언문이 아닌 함수 리터럴 표현식으로 해석된다.
//함수 리터럴은 함수 이름을 생략할 수 없다
(function bar(){
console.log('bar');
});
bar(); ReferenceError:bar is not defined
위 예제의 foo()는 단독으로 선언되었고, 함수 선언문이다.
하지만 연산자 ()내에 존재하는 함수 리터럴 bar은 함수 선언문으로 해석되지 않고 함수 리터럴 표현식으로 해석된다.
이처럼 이름이 있는 기명 함수의 리터럴은 코드의 문맥에 따라 선언문으로, 리터럴 표현식으로 해석된다.
함수 객체를 생성한다는 점에서 함수 선언문과 함수 리터럴 표현식은 동일하지만, 함수 호출에 차이가 있다.
위의 foo()는 호출할 수 있으나 bar()는 호출 할 수 없다.
함수 리터럴에서 함수의 이름은 함수 몸체 안에서 참조할 수 있다.(함수 몸체 안에서만 사용할 수 있는 식별자이다)
즉,함수 외부에서 함수 이름으로 함수 객체를 참조할 수 없다. 다시 말해, 함수를 가리키는 변수(식별자)가 존재하지 않다.
그래서 bar()는 호출 할 수 없다.
bar는 함수 몸체 안에서 식별할 수 있고, 함수 외부에서 bar함수를 가리키는 식별자가 존재하지 않으므로,
bar()호출 시 에러가 난다.
하지만 함수 선언문으로 선언한 foo()는 호출 시 에러가 발생하지 않는다.
foo()도 함수 몸체 안에서 사용 가능한 식별자이므로 foo()도 에러가 발생하여야 한다.
그러나 foo()는 호출 가능하다.
그 이유는 foo는 자바스크립트 엔진이 암묵적으로 생성한 식별자이기 때문이다.
자바스크립트 엔진은 함수 선언문을 해석해 함수객체를 생성한다.
이때, 함수 이름은 함수 몸체 안에서만 식별가능한 식별자이므로 함수 이름과 별개로 함수 객체를 호출하는 식별자가 필요하다.
함수 객체를 가리키는 식별자가 없으면, 함수 객체의 참조가 불가능하므로,
자바스크립트 엔진은 생성된 함수를 호출하기 위해 생성된 함수를 가리키는 함수 이름과 동일한 식별자를 생성하고,
함수 이름과 동일한 식별자는 함수를 가리킨다.
즉, 함수는 함수이름으로 호출하는 것이 아닌, 함수 객체를 가리키는 식별자로 호출하는 것이다.
foo()함수를 호출한 것은 JS 엔진이 암묵적으로 생성한 (함수 이름과 동일한) foo 식별자에 의해 호출되는 것이다.
함수 표현식
자바스크립트 함수는 객체 타입의 값이다.
자바스크립트의 함수는 값처럼 변수에 할당할 수 있고, 프로퍼티 값이 될 수 있고, 배열의 요소가 될 수 있다.
이처럼 값의 성질을 갖는 객체를 일급 객체라고 한다.
함수는 일급 객체이므로 함수 리터럴로 생성한 함수를 변수에 할당 할 수 있다.
이러한 정의 방식을 함수 표현식이라고 한다.
var add = function(x,y){
return x+y;
};
//함수 표현식의 예
함수 리터럴의 함수 이름은 생략 가능하다.(함수 표현식은 함수 이름을 생략하는 것이 일반적이다)
함수 선언문에서 함수 호출을 할 떄, 함수 이름으로 호출하는 것이 아닌, 함수 객체를 가리키는 식별자를 통해 호출한다고 하였다.
밑에서 foo(2,5)가 오류나는 이유도 함수 객체를 가리키는 식별자 add를 통해 함수 호출을 한 것이 아니라,
foo를 사용했기 때문이다.
var add = function foo(x,y){
return x+y;
}
//add는 foo라는 함수 객체를 가리키는 식별자이다.
//foo는 함수 이름이고, 함수 몸체 안에서 식별가능한 식별자이다.
console.log(add(2,5)); //7
console.log(foo(2,5));
//ReferenceError
//foo는 함수 몸체 안에서만 유효한 식별자이다. 식별자 add를 통해 함수를 호출해야 한다