🔑다양한 함수의 형태에 대해서 파헤쳐보자!
-WHAT IS❓
즉시 실행 함수란 함수 정의와 동시에 즉시 호출되는 함수 의미한다.
- 즉시 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없다.
-HOW TO USE❕❓
- 즉시 실행함수는 익명 혹은 기명 함수 함수 끝에 함수 호출 연산자, ()를 붙인 채 함수 전체를 그륩 연산자 (...)로 감싸준다.
- 즉시 실행함수는 익명함수를 사용하는 것이 일반적이다.
<script> // 익명 즉시 실행 함수 (function (){ let x = 3; let y = 5 return x+y; }()); </script>
- 그륩 연산자(...) 내의 기명함수는 함수 선언문이 아닌 함수 리터럴로 평가되기 때문에 함수 이름을 통해 즉시 실행 함수를 다시 호출할 수 없다.
<script> // 기명 즉시 실행 함수 (function multiply(){ let x = 3; let y = 5 return x+y; }()); multiply(); // 참조오류 </script>
- 그륩 연산자의 피연산자는 값으로 평가되어 기명 또는 무명함수를 그륩 연산자로 감싸면 함수리터럴로 평가되어 함수 객체가 된다.
<script> // 위 함수 내용 일치 // 익명 즉시 실행 함수 데이터 타입 console.log(typeof (function (){})); // function // 기명 즉시 실행 함수 데이터 타입 console.log(typeof (function multiply(){})); // function // 즉시 실행 함수 다른 연산자 사용 방식 </script>
- 즉시 실행 함수도 일반 함수처럼 값을 반환할 수 도 있으며 인수를 전달할 수 도 있다.
<script> // 즉시 실행 함수도 일반 함수 처럼 값을 반환 const multiply = (function(){ let x = 3; let y = 5; return x * y; }()); console.log(multiply) // 15 // 즉시 실행 함수도 일반 함수처럼 인수를 전달 multiply2 = (function(x, y){ return x * y; }(3, 5)); console.log(multiply2) // 15 </script>
-WHAT IS❓
재귀 함수란 자기 자신을 호출하는 행위, 재귀 호출을 수행하는 함수를 말한다.
- 즉시 실행 함수는 단 한 번만 호출되며 다시 호출할 수 없다.
-HOW TO USE❕❓
- 재귀 함수는 반복되는 처리를 위해 사용한다.
<script> // 반복문을 사용해 1-10까지 출력하는 함수 function countdonwWithFor(n) { for (let i = n; i >=0; i--) console.log(i); } countdonw(10) // 반복문 없이 재귀 함수를 사용해 구현하는 방식 function countdown(n){ if (n < 0) return; // 인수가 0보다 작아지면 종료 console.log (n) countdown2(n - 1); // 재귀 함수 호출 } countdonwWithFor(10) // 같은 결과가 나온다. countdown(10); </script>
- 자기 자신을 호출하는 재귀 함수를 사용해 반복되는 처리를 반복문 없이 구현
- 재귀 함수는 자신을 무한 재귀 호출한다. 따라서 재귀 함수 내에서 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들지 않으면 함수가 무한 호출되어 스택오버 플로 에러가 발생한다.
<script> // 팩토리얼은 1부터 자기 자신까지의 모든 양의 정수의 곱 // n! = 1 * 2 * ... * (n-1)* n // 1. 반복문 while로 구현한 팩토리얼 function factorialWithWhile(n) { if (n <= 1) return 1; let result = n; while (--n) result = result * n; return result; } // const factorial = function recursiveFuc(n) { if (n <= 1) return 1; return n * factorial(n-1); /*함수 표현식으로 정의한 함수 내부에선 함수 이름도 함수를 가리키는 식별자로도 재귀함수를 호출 할 수 있다.*/ } //단, 함수 외부에선 함수를 호출할 땐 반드시 함수를 가리키는 식별자로 해야한다. console.log(factorial(0)) // 0! = 1 console.log(factorial(1)) // 1! = 1 console.log(factorial(2)) // 2! = 2 * 1 = 2 console.log(factorial(3)) // 3! = 3 * 2 * 1 = 6 console.log((factorialWithWhile(3))) // 같은 결과가 나온다. </script>
-> 재귀 함수는 반복문을 사용하는 것 보다 재귀 함수를 사용하는 편이 더 직관적으로 이해하기 쉬울 때만 한정적으로 사용하는 것이 바람직하다.
-WHAT IS❓
중첩 함수란 함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라고 한다
중첩 함수를 포함하는 함수는 외부 함수라 부른다.
-HOW TO USE❕❓
- 중첩 함수는 자신을 포함하는 외부 함수를 돕는 헬퍼함수의 역할을 한다.
- 함수 선언문의 경우 if 문이나 for문 등의 코드 블록 내에서도 정의 가능하지만 호이스팅으로 인해 혼란이 발생할 수 있으므로 바람직하지 않다.
- 중첩 함수는 스코프와 클로저와 깊은 관련이 있다는 것을 기억하자.
<script> function outer(){ // 외부 함수 const x = 1; // 중첩 함수, 내부함수 function inner (){// 외부 함수를 돕는 헬퍼 함수 역할 // 외부 함수의 변수를 참조할 수 있음 const y = 3 console.log(x + y); } inner() } outer() </script>
-WHAT IS❓
콜백 함수란 함수의 매개변수를 통해 다른 함수 내부로 전달 되는 함수이며 고차함수(함수형 프로그래밍 패러다임에서)는 매개 변수를 통해 함수 외부에서 콜백함수를 전달 받은 함수를 의미한다.
- 아래 함수들은 공통적으로 반복하는 일을 수행하지만 하는 일의 내용이 다르기에 매번 함수를 새롭게 정의해야하는 단점이 있다.
<script> // 전달한 인수 n 만큼 일을 반복하는 함수1 function repeat1(n){ // 외부 함수 // i를 출력 for(var i = 0; i < n; i++) console.log(i); } repeat1(5 // 전달한 인수 n 만큼 일을 반복하는 함수2 function repeat2(n){ // 외부 함수 for(var i = 0; i < n; i++){ // i가 홀수 일 때만 출력 if (i % 2) console.log(i) } } repeat2(5) </script>
-HOW TO USE❕❓
- 콜백 함수를 통해서 함수를 합성을 하면 함수의 변하지 않는 공통 로직은 미리 정의해두고, 경우에 따라서 변경되는 로직은 추상화해서 함수 외부에서 함수 내부로
전달하여 위 코드의 단점을 해결할 수 있다.<script> // 외부에서 전달받은 함수 f를 n만큼 반복 호출하는 함수 function repeat(n, f){ // 변경 되는 함수를 f로 추상화하여 외부에서 전달받는다. for(var i = 0; i < n; i++) { f(i); // i를 전달하면서 함수 f를 호출 } } const logAll = function(i){ // 모든 0부터 n직전까지 출력하는 logAll 함수 console.log(i) }; repeat(5, logAll)// 반복 호출할 logAll 함수(콜백함수)를 인수로 전달한다. const logOdds = function(i){ // 0부터 n직전까지 중 홀수만 출력하는 logOdds 함수 if (i % 2) console.log(i); }; repeat(5, logOdds)// 반복 호출할 logOdds 함수(콜백함수)를 인수로 전달한다. </script>
- 중첩 함수처럼 콜백 함수 역시 고차함수에 전달되어 헬퍼함수의 역할을 하지만 중첩 함수는 고정되어 교체하기 어렵지만 콜백 함수는 외부에서 고차함수 내부로 주입할 수 있다.
-> 따라서 고차함수는 콜백함수를 자신의 일부분으로 합성하여 교체가 보다 유연하다.
<예시1> 콜백함수가 고차 함수 내부에서만 호출 되는 경우
- 콜백 함수를 익명 함수 리터럴로 정의하면서 곧바로 고차 함수에 전달하면 콜백 함수로서 전달된 함수 리터럴은 고차 함수가 호출 될 때마다 평가되어 함수 객체를 생성한다.
<script> // 익명 함수 리터럴을 콜백함수로 고차 함수에 전달 function repeat(5, function(i){ // 익명 함수 리터럴은 repeat 함수를 호출 할 때마다 평가되어 함수 객체를 생성한다. if (i % 2) console.log(i); }); </script>
<예시2> 콜백 함수를 다른 곳에서도 호출 할 필요가 있거나, 콜백 함수를 전달받는 함수가 자주 호출되는 경우
- 함수 외부에서 콜백 함수를 익명 함수 리터럴로 정의한 후 함수 참조를 고차 함수에 전달하면 고차 함수가 호출 될 때마다 콜백 함수가 생성된다.
<script> //logOdds 함수는 단 한 번만 생성된다. const logOdds = function(i){ if (i % 2) console.log(i); }; // 고차 함수에 함수 참조를 전달한다. repeat(5, logOdds) </script>
<예시3> 콜백함수는 함수형 프로그래밍 패러다임(고차함수) 외에도 비동기 처리(이벤트, Ajax 통신, 타이머 함수 등)에 활용가능하다.
<script> // 예시3-1, 콜백 함수를 사용한 이벤트 처리 document.getElementById('btn').addEventListener('click', function(){ console.log('btn clicked') // btn 버튼 클릭하면 콜백 함수 실행 }) // 예시 3-2.콜백 함수를 사용한 비동기 처리 setTimeout(function{ console.log('passed one min') // 1초 후 메세지 출력 }, 3000) </script>
<예시4> 콜백함수는 배열 고차 함수에도 사용된다.
<script> // 예시 4-1, 콜백 함수를 사용하는 고차 함수 map var result = [1,2,3].map(function(item) { return item * 2; }) console.log(result) // [2, 4, 6] // 예시 4-2, 콜백 함수를 사용하는 고차 함수 filter result = [1,2,3].filter(function(item) { return item % 2; }) console.log(result) // [1, 3] // 예시 4-3, 콜백 함수를 사용하는 고차 함수 reduce result = [1,2,3].reduce(function(acc, cur) { return acc + cur; }) console.log(result) // 6 </script>
-WHAT IS❓
순수 함수
란 함수형 프로그래밍에서 어떤 외부 상태에 의존하지도 않고 변경하지 않는, 부수효과가 없는 함수이다.- 반대로
비 순수 함수
는 외부 상태에 의존하거나 함수의 외부 상태를 변경하는 부수효과가 있는 함수를 의마한다.
<script> let count = 0; // 순수 함수 increase는 동일한 인수가 전달되면 언제나 동일 한 값을 반환 function increase(n){ return ++n; } // 순수 함수가 반환한 결과값을 변수에 재할당해서 상태를 변경 let newCount = increase(count); console.log(count) count = increase(count); console.log(count) let count2 = 0; // 비순수 함수 increase에 의해 count2에 값이 변화한다. function increase(){ return ++count2; // 외부 상태를 직접 참조하여 외부 상태를 변경 } // 비 순수 함수는 외부 상태 count를 변경하므로 상태 변화 추적이 어렵다 increase(); console.log(count2) increase(); console.log(count2) </script>
순수 함수
는 오직 매개변수를 통해 함수 내부로 전달된 인수에게만 의존해 반환값을 만들기 때문에 함수의 외부 상태를 변경하지 않는다.비 순수 함수
는 외부 상태에 의존하거나 외부 상태를 변경할 수 있다.
-> 외부 상태를 변경하면 상태 변화를 추적하기 어렵기 때문에 외부 상태 변경을 지양하는 순수 함수 사용하는 것이다 좋다.
- 함수형 프로그래밍은 순수 함수와 보조함수의 조합을 통해 외부 상태를 변경하는 부수 효과를 최대한 억제해 불변성을 지향하는 프로그래밍 패러다임으로 이를 통해 오류를 피하고 프로그램의 안정성을 높일 수 있다.
- 책 - 딥다이브 자바스크립트