[Javascript] 함수 총정리 ② | 다양한 종류의 함수들

Re_Go·2023년 12월 8일
0

Javascript

목록 보기
15/44
post-thumbnail

1. 다양한 함수 형태들

앞서 소개해 드린 장에서는 함수의 기본 구성 및 정의 종류들에 대해서 알아봤는데요. 이러한 함수들은 그 정의에 대한 종류들 뿐만 아니라 함수 자체의 쓰임새에 따라 좀 더 다양하고 독특한 구성을 가진 함수들 또한 존재합니다.

이번 장에서는 독특한 특징들로 구성된 함수들에 대해서 살펴보도록 하겠습니다.

2. 즉시 실행 함수(immediately invoked Function Expression)

런타임때에 함수 정의와 동시에 즉시 호출되는 함수이며 보통 함수 리터럴로 생성하는 함수 선언문의 형태를 띄우고 있습니다. 이러한 즉시 실행 함수는 기명 함수도 사용이 가능하나 보통은 익명 함수를 사용하는 것이 일반적입니다.

이 함수는 한 번 실행이 된 후에는 후에 호출이 불가능 합니다. 하지만 함수 표현식을 사용시 인자를 넘겨 받는 작업으로도 사용이 가능하며, 후에 살펴볼 클로저에서 외부 스코프에 불필요한 변수를 노출시키지 않고, 모듈 패턴이나 정보 은닉 등의 디자인 패턴을 구현하는 용도로 사용됩니다.


// ① 일반적인 즉시 실행 함수 선언 방법)

(function(){
  let a = 1, b = 2;
  console.log(a+b);
})(); // 함수의 구분자 바로 앞에 비어있는 쌍괄호를 넣어 이 함수가 즉시 실행 함수임을 나타냅니다.
// 런타임이 실행되면 해당 함수는 선언과 함께 바로 콘솔의 값을 출력할 것입니다.


// ② 즉시 실행 함수의 값 반환)

let add = (function(){
  let a = 1, b = 2;
  return a+b;
}()); // 함수 표현식 방법으로 add 변수 안의 함수를 선언과 함께 즉시 실행하여 반환값을 add에 저장합니다.


// ④ 즉시 실행 함수에 인자를 전달하는 법)

let add = (function(a,b){ // 매개변수를 입력합니다.
  return a+b;
}(3,5)); // 구분자 앞 쌍괄호에 전달할 인자를 입력하면 그 값을 전달 받아 함수 실행 후 값을 add에 반환합니다.

3. 재귀 함수(recursive call)

앞서 함수 1장의 함수 선언문에도 언급을 했던 재귀 함수를 자세히 설명해 드리자면

재귀 함수는 코드 블록 내에 자기 자신을 호출하는 함수이며, 호출 방법으로 함수의 이름을 활용합니다. 재귀 함수의 경우 무한히 자신을 반복하는 함수의 구현 특성상

조건문을 걸어 특정 조건에서 break를 걸거나 return문을 새로 주어 빠져나가는 코드부를 구현해야 합니다.

이러한 재귀 함수는 수학적 문제를 해결하는 작업에 주로 사용됩니다.

// ① for 반복문을 구현한 재귀 함수)

function countdown(n){
  if(n < 0) return; // 만약 전달 받은 매개변수가 0보다 작을 경우 return으로 함수 종료
  console.log(n) // if 조건문이  거짓일 경우 아래의 매개변수의 현재값을 콘솔에 출력 하고
  countdown(n - 1); // 매개변수에서 -1한 값을 다시 countdown 함수를 호출하여 전달.
}

countdown(10); //카운트다운 함수 호출

// ② 팩토리얼을 구현한 재귀 함수) 

function fatorial(n){ //인자를 받아서
  if (n <= 1 )return 1; // 매개변수의 값이 1보다 작은 0 이하의 음수라면 1을 반환하고
  return n * fatorial(n - 1); // 조건에 맞지 않아 실행되는 다음 return 문, n이 1 이상일 때는 매개변수에 매개변수 - 1 연산처리 한 결과값을 곱해 반환합니다.
}
console.log(fatorial(5)); // 재귀 함수에 5를 인자로 전달.


// 해당 팩토리얼 재귀 함수의 로직은 for문의 다음 코드 블록과 같습니다.
var result = 1; // 변수를 저장할 result 변수 초기화

for (var i = 1; i <= 5; i++) { // 1부터 5까지 차례대로 곱셈
    result *= i;
}

console.log(result); // 출력: 1 * 2 * 3 * 4 * 5 = 120

4. 콜백 함수(callback function)

인자로 넘겨줄 때 포함 되는 함수를 의미하며 이때 콜백 함수를 인자로 넘겨 받는 함수를 고차 함수(higher-order function)이라고 부릅니다.

이 콜백 함수는 앞서 소개한 다른 함수의 종류와는 다르게 매우 중요한 개념 중 하나이므로 특히 사용법을 익히는 것이 중요합니다.

function processArray(arr, callback) { // 배열과 콜백함수를 인자로 전달 받아
  for (let i = 0; i < arr.length; i++) { // 배열의 길이만큼 반복하는 동안
    callback(arr[i]); //콜백함수를 호출하여 배열의 i번째의 값을 인자로 또 전달하면 콜백 함수 안에서 인덱스의 i번째 값을 출력합니다.
  }
}

function logItem(item) { // item을 출력하는 함수 정의
  console.log(item);
}

const myArray = [1, 2, 3, 4, 5]; // 다섯개의 값이 들어있는 변수 myArray를 선언 및 초기화

processArray(myArray, logItem); // 배열 변수와 item 콘솔 출력 함수를 인자로 전달

5. 순수 함수(Pure Function)와 비순수 함수 (Impure Function)

순수 함수는 어떠한 외부 상태에도 달라지지 않으며 그 반대로 외부의 상태를 변경하지 않고, 부수 효과가 없는 함수를 의미하며, 비순수 함수는 그의 반대 되는 개념의 함수입니다.

즉 함수가 외부의 어떠한 변수나 코드에 직접적으로 영향을 주지 않을 경우 순수 함수이고, 그 반대로 영향을 줄 경우 비순수 함수가 된다는 개념 정도로 이해하시면 됩니다.

// ① 순수 함수 예시) 오직 인자로 넘겨 받은 값을 사용하고 외부의 변수나 함수에 영향을 주지 않은 상태에서 값을 생성하고 반환합니다.

let count = 0; 

function increase(n){
  return ++n; // 동일한 입력에 대한 동일한 결과를 반환합니다.
}

count = increase(count); // count 변수에 increase 함수를 호출하여 반환된 값 0을 count에 재할당.
console.log(count); // 반환 받은 count의 값 1 출력


// ② 비순수 함수 예시) 외부 변수(count)의 상태를 변경하는 부수효과를 가집니다.

let count = 0; // 초기 카운트의 값은 0

function increase(){
  return ++count; // 외부에 있는 count 값을 직접적으로 변경
}

increase(); // count 함수를 증가 시키는 함수 호출
console.log(count) // 함수에 의해 변경 된 값 1 출력

6. 중첩 함수(Nested Functions)

중첩 함수는 하나의 함수 내부에서 다른 함수를 정의하는 작성법을 의미합니다. 이렇게 정의된 중첩 함수는 외부 함수의 스코프에 접근할 수 있으며, 클로저와의 연관이 깊은 중첩 함수는 향후 살펴볼 클로저에서 상위 함수의 변수들에 대한 직접 접근은 불가능 하지만,

해당 변수들을 이용하는 클로저 역할을 하는 함수들을 이용해 해당 변수들의 상태 관리 또한 용이하게 가능하고, 또 변수들의 보안 유지 또한 확보할 수 있다는 점에서 아주 중요한 개념의 함수 중 하나입니다.

// ① 중첩 함수의 간단한 사용 예시

function calculateRectangleArea(width, height) { // 매개변수로 입력을 받았으므로 함수의 매개변수에 직접적으로 접근하는 것은 불가능 하지만
    function multiply() { // 해당 매개변수들을 중첩 함수에서 사용이 가능합니다.
        return width * height;
    }

    return multiply(); // 중첩 함수 호출
}

const area = calculateRectangleArea(10, 5);
console.log(area); // 출력: 50

7. 화살표 함수 (Arrow Function)

ES6에 등장한 함수 정의 방식으로 function 키워드 대신 fat arrow(=>)를 사용하여 기존의 함수 정의 방식보다도 더 간결하고, 내부 동작 또한 더 간략하게 만들 수 있는 가장 강력한 함수 정의 방식입니다.

특히 매개변수가 하나일 경우 괄호를 생략하는 것마저 가능하며, 표현식이 하나일 경우 해당 표현식이 값으로 평가될 수 있는 표현식일 경우 중괄호 또한 생략이 가능합니다.

이 말은 반대로 값으로 평가될 수 없는 대입문과 같은 표현식일 경우 중괄호 생각이 불가능하다는 것을 의미합니다.

특히 이러한 화살표 함수는 콜백 함수로서 정의할 때 매우 유용하며, 일반 함수와의 가장 큰 차이점은 this 키워드의 동작 방식에서의 차이점을 둘 수 있습니다. 자체 this 키워드를 가지고 있는 일반 함수와는 다르게 자체 this를 가지고 있지 않고, 외부 스코프에 this가 결정 된다는 차이점을 예로 들 수 있습니다.

// ① 화살표 함수 기본 예시

const addNumbers = (a, b) => {a+b} // 화살표 함수 기본 정의 방식


// ② 생략 가능한 요소 예시
const returnStringToFloat = a => return a ** 2; // 매개변수가 하나일 경우 매개변수의 괄호 생략 가능, 또한 표현식이 한 줄일 경우 마찬가지로 중괄호 생략 가능. 단 값으로 평가되는 표현식에 한해서만 중괄호 생략 가능.
// ③ this 키워드 동작 예시


function NormalFunction() { // 생성자 함수를 생성합니다.
  this.value = 42; // 이때의 this 인스턴스 입니다.

  this.normalFunction = function() { // 인스턴스의 첫번째 메서드는 this.value를 출력하는 일반 함수로
  console.log("Normal Callback:", this.value);
  };

  this.arrowFunction = () => { // 마찬가지로 두번째 메서드도 this.value를 출력하는 화살표 함수로 정의합니다.
    console.log("Arrow Callback:", this.value);
  };
}

const example = new NormalFunction(); // 인스턴스 생성

example.normalCallback(); // 출력: Normal Callback: undefined, 또는 오류가 표시되는데 그 이유는 일반 함수의 this는 차후 배우게 될 전역 객체(window 또는 global)을 의미하기 때문에 해당 메서드는 window.value(아직 선언되지 않은 value의 값)을 출력하려 하는 셈인 것이죠.
example.arrowCallback();  // 출력: Arrow Callback: 42, 반면 화살표 함수의 this는 인스턴스가 만들어지는 시점에 결정되므로 this(인스턴스)의 value 42가 정상적으로 호출됩니다.


// ③ 객체 리터럴로 반환시 주의사항) 반환할 값이 객체 리터럴인 경우 해당 객체 리터럴을 반드시 소괄호로 감싸주어야 합니다. 만약 소괄호를 생략한다면 함수 몸체를 감싸는 중괄호로 인식하고, return문이 생략된 상태이므로 결과적으로 undefined가 반환되게 됩니다.
const makeStudent = (name, className) => ({name, className}); // 입력받은 매개변수를 name과 className 프로퍼티에 담아 객체 리터럴로 반환)
const student1 = makeStudent('박종민', '3반');
console.log(student1) // { name: '박종민', className: '3반' } 으로 출력됩니다.
profile
인생은 본인의 삶을 곱씹어보는 R과 타인의 삶을 배워 나아가는 L의 연속이다.

0개의 댓글