즉시 실행 함수
함수 정의와 동시에 호출되는 함수로 단 한번만 호출되며 다시 호출할 수 없다.
// 익명 즉시 실행 함수
(function () {
var a = 3;
var b = 5;
return a * b
}());
// 기명 즉시 실행 함수
(function foo() {
var a = 3;
var b = 5;
return a * b
}());
foo() // ReferenceError: foo is not defined
그룹 연산자(..) 내의 기명 함수는 함수 선언문이 아니라 함수 리터럴로 평가되어 다시 호출 할 수 없다.
즉시 함수
를 그룹 연산자로 감싸는 이유는 먼저 함수 리터럴로 평가해서 함수 객체를 생성하기 위해서 이기 때문이다.
즉시 실행 함수
도 일반 함수 처럼 값을 반환할 수 있고 인수를 전달 할 수 있다.
var res = (function () {
var a = 10;
var b = 2;
return a * b;
}());
console.log(res); // 20
var res = (function (a, b) {
return a * b;
}(10, 2));
console.log(res) // 20
재귀 함수
함수가 자기자신을 호출하는 것을 재귀 호출이라 한다. 즉, 재귀 함수
는 재귀 호출을 반복 수행하는 함수이다.
재귀 함수
는 반복되는 처리를 위해 사용된다.
function count(n) {
for(let a = n; a >= n; n++) {
console.log(a)
}
}
count(10);
// 위 코드를 반복문 없이 구현하기
function count(n) {
if(n < 0) return;
console.log(n)
count(n - 1);
}
count(10)
이처럼 자기자신을 호출하는 재귀 함수
를 사용하면 반복되는 처리를 반복문 없이 구현할 수 있다.
function factoial() {
if(n <= 1) return 1;
return n * factoial(n - 1);
}
// 팩토리얼 함수를 while 반복문을 이용해 구현
function factoial() {
if(n < 1) return 1;
var res = n;
while (--n) res *= n;
return res;
}
재귀 함수
는 반복문을 사용했을때 보다 가독성이 좋아질때만 사용하는 것이 좋다. 왜냐하면 스택오버 플로우에 빠질 위험이 크기 때문이다.
중첩 함수
함수 내부에 정의된 함수를 중첩 함수
또는 내부 함수
라고 부른다. 중첩 함수
는 외부 함수에서만 호출할 수 있다. 일반적으로 중첩 함수
는 자신을 포함한 외부 함수를 돕는 헬퍼 함수 역할을 한다.
function outer() {
var x = 1;
function inner() {
var y = 2;
console.log(x + y) // 3
}
inner()
}
outer()
ES6부터 함수 정의는 문이 위치할 수 있는 문맥이라면 어디든지 가능하다. 함수 선언문의 경우 ES6 이전에 는 코드의 최상위 또는 함수 내부에서만 정의 할 수 있었지만 ES6부터는 if 문이나 for 문 등의 코드 블록 안에서도 정의할 수 있다.
하지만 이는 함수 호이스팅으로 인해 혼란이 발생할 수 있어 별로 바람직하지 않다.
콜백 함수
function repeat(n) {
for(var i = 0; i < n; i++) console.log(i)
}
repeat(5)
repeat 함수는 매개변수를 통해 전달받은 숫자 만큼 반복하며 log를 호출한다. 이때 repeat 함수는 log에 강하게 의존하고 있어서 다른 일을 하려면 새롭게 정의해야한다.
function repeatOdd(n) {
for(var i = 0; i < n; i++) {
if(i % 2) console.log(i)
}
}
repeatOdd(5) // 1 3
위 두 함수는 일부분만 다르기 때문에 새롭게 정의하는 것은 효율성이 떨어지기 때문에 로직을 추상화시켜 공통부분을 처리해 해결할 수 있다.
// 외부에서 n만큼 f를 반복한다.
function repeat(n, f) {
for(let i = 0; i < n; i++) {
f(i)
}
};
var logAll = function(i) {
console.log(i);
};
repeat(4, logAll);
var logOdds = function(i) {
if(i % 2) console.log(i);
};
repeat(5, logOdds);
함수 매개변수를 통해 다른 함수의 내부로 전달되는 함수는 콜백 함수
라고 하며, 매개변수를 통해 함수의 외부에서 콜백함수를 전달 받은 함수를 고차 함수
라고 한다. 즉, 고차 함수
는 콜백함수를 자신의 일부분으로 합성한다.
// 익명 함수 리터럴을 콜백 함수로 고차 함수에 전달한다.
// 익명 함수 리터럴은 repeat함수가 호출될 때마다 평가되어 함수 객체를 생성한다.
repeat(5, function(i) {
if(i % 2) console.log(i);
}); // 1, 4
이때 콜백 함수로서 전달된 함수 리터를은 고차 함수가 호출될 때마다 평가되어 함수 객체를 생성한다.
따라서 콜백 함수를 다른 곳에 전달할 필요가 있거나, 전달받는 함수가 자주 호출 된다면 함수 외부에서 콜백 함수를 정의한 후 함수 참조를 고차 함수에 전달하는 편이 효과적이다.
// logOdds 함수는 단 한 번만 생성됨
var logOdds = function(i) {
if(i % 2) console.log(i)
}
// 고차 함수에 함수 참조 전달.
repeat(5, logOdds);
위 예제 처럼 콜백 함수(logOdds)
는 단 한 번만 생성된다. 하지만 콜백 함수
를 함수 리터럴로 정의해 바로 전달하면 고차함수(repeat)
가 호출될 때마다 콜백 함수를 생성된다.
순수 함수와 비순수 함수
함수형 프로그래밍에서 어떤 외부상태에 의존하지 않고 변경하지도 않는, 즉 부수효과가 없는 함수를 순수 함수
라 하고, 외부 상태에 의존하거나 외부 상태를 변경하는, 즉 부수효과가 존재하는 함수를 비순수 함수
라고 한다.
순수 함수
는 동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수이다. 외부 상태에는 전역 변수, 서버 데이터, 파일, console, DOM등이 있다. 외부 상태에는 의존하지 않고 함수 내부 상태에만 의존 한다 해도 내부 상태가 호출 될 때마다 변화하는 값이라면 순수 함수가 아니다.
var count = 0
// 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일한 값을 반환
function increase(n) {
return ++n
}
// 순수 함수가 반환한 값을 변수에 재할당해서 상태를 변경
count = increase(count);
비순수 함수
는 외부 상태에 의존한다. 또한 순수 함수와 달리 함수의 외부 상태를 변경하는 부수 효과가 있다.
var count = 0;
// 비순수 함수
function increase() {
return ++count // 외부상태에 의존하며 외부 상태를 변경한다.
}
// 비 순수 함수는 외부 상태를 변경하므로 상태 변화를 추적하기 어려워진다.
increase();
인수를 전달받지 않고 함수 내부에서 외부 상태를 직접 참조하면 외부 상태에 의존하게 되어 반환값이 변할 수 있고 외부 상태도 변경할 수 있으므로 비순수 함수
가 된다
함수 내부에서 함수 외부 상태를 직접 참조하지 않아도 매개변수를 통해 객체를 전달 받으면 비순수 함수
가 된다.
'Javascript' 카테고리의 다른 글
자바스크립트 - var, const, let? (0) | 2024.04.09 |
---|---|
자바스크립트 - 스코프 (0) | 2024.04.09 |
자바스크립트 함수란? (0) | 2024.04.09 |
원시 값과 객체를 비교해보자 (0) | 2024.04.09 |
객체 리터럴은 무엇이냐? (0) | 2024.04.09 |