on
[Javascript]함수(3)
함수의 다양한 형태들!
함수의 형태
1. 즉시 실행 함수(Immediately invoked function)
함수 정의와 동시에 즉시 호출되는 함수를 즉시 실행 함수라고 한다. 단 한번만 호출되며 다시 호출할 수 없다. 따라서 익명함수를 사용하는 것이 일반적이다. 그룹연산자()
내의 함수는 함수리터럴로 평가되며, 함수 선언문과 다르게 함수 이름과 같은 식별자를 만들어 함수 선언문을 할당하지 않으므로 외부에서 즉시 실행 함수의 함수를 다시 호출할 수 없다.
// 기명 즉시 실행 함수
(function foo() {
var a = 3;
var b = 5;
return a * b;
})();
foo(); // ReferenceError: foo is not defined
즉시 실행 함수는 반드시 그룹연산자로 감싸야한다. 그렇지 않을 경우 자바스크립트 엔진이 암묵적으로 중괄호 뒤에 세미콜론을 추가하기 때문에 에러가 발생한다.
function () { // SyntaxError: Function statements require a function name
// ...
}()
function foo() {
// ...
}(); // SyntaxError: Unexpected token ')'
function foo() {}(); // => function foo() {};();
(); // SyntaxError: Unexpected token )
그룹연산자만 즉시 실행 함수가 되는 것은 아니다. 함수를 함수 리터럴로 평가해서 함수 객체를 생성할수 있다면 다른 연산자를 사용하는 것도 가능하다.
(function () {
// ...
})();
!(function () {
// ...
})();
+(function () {
// ...
})();
즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있고, 인수를 전달할 수도 있다.
// 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 있다.
var res = (function () {
var a = 5;
var b = 10;
return a * b;
})();
console.log(res); // 50
// 즉시 실행 함수에도 일반 함수처럼 인수를 전달할 수 있다.
res = (function (a, b) {
return a * b;
})(3, 4);
console.log(res); // 12
2. 재귀 함수(recursive call function)
함수가 자기 자신을 호출하는 것을 재귀 호출이라고 한다.
function countdown(n) {
if (n < 0) return;
console.log(n);
countdown(n - 1); // 재귀 호출
}
countdown(10);
재귀 함수로 반복문 대신하여 사용할 수 있으나, 탈출 조건을 반드시 만들어야하고 그렇지 않을 경우 스택 오버플로 에러가 발생함으로 유의해야 한다. 알고리즘을 위한 경우 많이 사용된다.
//팩토리얼 재귀 함수
function factorial(number) {
var product = 1;
for (var i = number; i >= 1; --i) {
product *= i;
}
return product;
}
factorial(4);
3. 중첩 함수(nested function)
함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라고 한다. 그리고 중첩 함수를 포함하는 함수를 외부 함수 라고 한다. 내부 함수는 외부 함수 내부에서만 호출할 수 있다. 일반적으로 내부 함수는 외부 함수를 돕는 헬퍼 함수의 역할을 한다.
function outer() {
var x = 1;
// 내부 함수
function inner() {
var y = 2;
// 외부 함수의 변수를 참조할 수 있다.
console.log(x + y); // 3
}
inner();
}
outer();
inner(); // 에러남, 내부 함수는 외부 함수 안에서만 호출 할 수 있다.
4. 콜백 함수(callback function)
함수의 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백함수라고 한다. 매개변수를 통해 외부에서 콜백 함수를 전달받는 함수를 고차함수 라고 한다. 고차 함수는 콜백 함수를 자신의 일부분으로 합성한다.
// 외부에서 전달받은 f를 n만큼 반복 호출한다
function repeat(n, f) {
for (var i = 0; i < n; i++) {
f(i); // i를 전달하면서 f를 호출
}
}
var logAll = function (i) {
console.log(i);
};
// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logAll); // 0 1 2 3 4
var logOdds = function (i) {
if (i % 2) console.log(i);
};
// 반복 호출할 함수를 인수로 전달한다.
repeat(5, logOdds); // 1 3
콜백 함수가 고차 함수 내부에서만 호출된다면, 콜백 함수를 익명 함수 리터럴로 정의하면서 곧바로 고차 함수에 전달하는 것이 일반적이다.
repeat(5, function (i) {
if (i % 2) console.log(i);
}); // 1 3
인수로 함수 리터럴을 직접 작성하여 전달할 때 유의할 점은, 콜백 함수로 전달된 함수 리터럴은 고차 함수가 호출될 때마다 평가되어 함수 객체를 생성한다. 따라서 콜백 함수가 다른 곳에서 호출 할 필요가 있거나, 고차 함수가 너무 자주 호출된다면 콜백 함수를 고차 함수 외부에서 정의한 뒤 전달하는 편이 효율 적이다.
// logOdds 함수는 단 한 번만 생성된다.
var logOdds = function (i) {
if (i % 2) console.log(i);
};
// 고차 함수에 함수 참조를 전달한다.
repeat(5, logOdds); // 1 3