-
함수 이름과 기명함수, 익명함수Studying/JavaScript 2021. 9. 13. 00:58
1. 함수 객체 식별자와 함수 이름
다음과 같이 두 수를 더하는 함수를 함수 표현식으로 정의하고 호출해 보자.
const addTwoNums = function add(a, b) { return a + b; }; console.log(addTwoNums(2, 5)); // 7
이때 함수 이름은 'add'이고, 'addTwoNums'는 add 함수 객체를 참조하는 식별자이다.
함수 이름 add로 함수를 참조하려고 하면const addTwoNums = function add(a, b) { return a + b; }; console.log(add(2, 5)); // ReferenceError: add is not defined
add가 정의되지 않았다며 ReferenceError가 발생하는 것을 볼 수 있다.
즉, 함수 이름으로 함수를 호출할 수 없으므로 함수 객체를 addTwoNums라는 변수에 할당하여 함수 객체를 가리키게 하고, 이 식별자로 함수를 호출하는 것이다.
위에서 정의한 함수 객체를 브라우저 콘솔에서 console.dir로 확인해 보면위와 같이 함수 객체의 여러 프로퍼티 중 키가 name인 프로퍼티가 존재하고, 이 프로퍼티의 값이 "add"인 것을 확인할 수 있다.
즉, 함수 이름은 함수 객체의 식별자로서가 아니라 함수 객체의 프로퍼티로서 존재한다.
그렇다면 함수 이름은 언제 사용하는 것일까?
함수 몸체 안에서는 함수 이름이 참조할 수 있는 식별자가 된다.
다시 말해 함수 내부에서 함수 자기 자신을 호출하는 상황, 즉 재귀함수가 재귀 호출을 할 때 함수 이름으로 자신을 호출할 수 있다.const seriesFromOne = function series(n) { return n === 1 ? 1 : n + series(n - 1); }; console.log(seriesFromOne(9)); // 45
다음과 같이 함수 내부에서 자기 자신을 함수 이름이 아닌 함수 객체의 식별자로 호출할 때에도 동일한 결과를 얻을 수 있다.
const seriesFromOne = function series(n) { return n === 1 ? 1 : n + seriesFromOne(n - 1); }; console.log(seriesFromOne(9)); // 45
하지만 위의 두 호출 방식에는 차이가 있다. 함수 이름으로 재귀 호출을 하면 함수 스코프 안의 식별자인 series로 함수를 호출하지만, 함수 객체의 식별자로 호출을 하면 함수의 상위 스코프에서 식별자 seriesFromOne을 찾아 호출하게 된다.
series 함수 내부에 함수 객체 식별자와 동일한 식별자의 함수를 정의해 보자.const seriesFromOne = function series(n) { console.log('Outer function called'); const seriesFromOne = function (n) { console.log('Inner funcion called'); return (n * (n + 1)) / 2; }; return seriesFromOne(n); }; console.log(seriesFromOne(9));
이때 바깥의 함수가 호출된 뒤, 함수 내부에서 seriesFromOne 함수를 호출하면 바깥의 함수가 아닌 함수 내에서 정의한 함수가 호출되어 재귀 호출이 되지 않았음을 알 수 있다.
2. 기명함수와 익명함수
기명함수(named function)란 이름이 있는 함수, 익명함수(무명함수, anonymous function)란 이름이 없는 함수를 말한다.
여기에서 말하는 이름이란 앞서 살펴본 함수 이름을 뜻한다.
위에서 함수를 표현식으로 정의하였다.const addTwoNums = function add(a, b) { return a + b; }; console.log(addTwoNums(4, 8)); // 12
위 함수를 정의할 때 add라는 함수 이름을 나타내었으므로 위의 함수는 기명함수이다.
표현식에서는 함수를 다음과 같이 함수 이름을 생략한 익명함수로 나타낼 수 있고, 일반적으로 함수 표현식에서는 함수 이름을 생략한다.const addTwoNums = function (a, b) { return a + b; }; console.log(addTwoNums(4, 8)); // 12
이 익명함수를 브라우저 콘솔에서 확인해 보면
name 프로퍼티의 값이 "addTwoNums"인 것을 볼 수 있다.
즉, 익명함수의 함수 이름은 함수 객체 식별자와 동일하게 생성된다.
함수 표현식으로 함수를 정의하는 상황이 아닐 때에도 항상 기명함수와 익명함수 모두로 함수를 정의할 수 있는 것은 아니다.
함수 선언문으로 함수를 정의할 때에는 함수 이름을 생략할 수 없다. 다시 말해, 항상 기명함수로 함수를 정의해야 한다.function add(a, b) { return a + b; } console.log(add(4, 8)); // 12
함수 선언문으로 함수를 정의하면 자바스크립트 엔진은 함수 객체의 식별자를 함수 이름과 동일한 이름으로 생성해 준다.
따라서 이 때에는 함수 이름 add(와 같은 이름의 함수 객체 식별자)로 함수를 호출할 수 있다.
한편 ES6에서 도입된 화살표 함수로 함수를 정의할 때에는 항상 익명함수로 정의해야 한다.const addTwoNums = (a, b) => a + b; console.log(addTwoNums(4, 8)); // 12
그리고 이 때에도 표현식 익명함수와 마찬가지로 함수 객체의 name 프로퍼티 값이 함수 객체의 식별자와 동일하게 생성된다.
표현식과 비교하여 prototype 프로퍼티가 없다는 차이도 있지만 이 점은 나중에 알아보기로 하자.반응형'Studying > JavaScript' 카테고리의 다른 글
Date 생성자함수, 프로토타입 객체의 프로퍼티 (0) 2021.10.19 표준 빌트인 객체 Date (0) 2021.10.12 .filter().map()과 .reduce() (0) 2021.10.04 Array.prototype.sort() 메서드 (0) 2021.10.03 함수 호출 방식에 따른 this 바인딩 (0) 2021.09.28