웹개발/javascript

[자바스크립트] 함수

joamashi 2024. 8. 4. 02:54

코드의 재사용과 효율성을 위한 핵심

자바스크립트 함수는 특정 작업을 수행하는 코드 블록입니다. 마치 레시피와 같이, 함수는 주어진 입력값(재료)을 가지고 특정한 결과값(요리)을 만들어냅니다. 함수를 사용하면 코드를 모듈화하고 재사용성을 높여 효율적인 프로그래밍이 가능합니다.

함수의 기본 구조

function 함수이름(매개변수1, 매개변수2, ...) {
  // 함수 내부에서 실행될 코드
  return 반환값; // (선택 사항)
}
  • 함수이름: 함수를 식별하기 위한 고유한 이름입니다.
  • 매개변수: 함수에 전달되는 값을 받는 변수입니다. 여러 개의 매개변수를 쉼표로 구분하여 사용할 수 있습니다.
  • 함수 내부 코드: 함수가 수행할 실제 작업을 포함하는 코드 블록입니다.
  • return: 함수의 실행 결과를 반환합니다. return 문을 생략하면 undefined가 반환됩니다.

함수를 사용하는 이유

  • 코드 재사용: 동일한 코드를 여러 번 반복하지 않고 함수를 호출하여 간편하게 사용할 수 있습니다.
  • 코드 가독성 향상: 복잡한 코드를 작은 함수 단위로 나누어 코드의 구조를 명확하게 만들고 이해하기 쉽게 합니다.
  • 유지보수 편의성: 함수 단위로 코드를 관리하면 오류 발생 시 특정 함수만 수정하면 되므로 유지보수가 용이합니다.
  • 추상화: 복잡한 로직을 함수로 감싸서 내부 구현을 숨기고 간단한 인터페이스만 제공할 수 있습니다.

함수의 종류

  • 함수 선언: 가장 일반적인 함수 선언 방식입니다.
  • 함수 표현식: 변수에 함수를 할당하는 방식입니다.
  • 화살표 함수: ES6에서 도입된 간결한 함수 표현 방식입니다.
  • 생성자 함수: 객체를 생성하는 데 사용되는 함수입니다.
// 함수 선언
function greet(name) {
  console.log("안녕하세요, " + name + "님!");
}

// 함수 호출
greet("홍길동");

// 함수 표현식
const sum = function(a, b) {
  return a + b;
};

// 화살표 함수
const multiply = (x, y) => x * y;

더 알아보기

  • 매개변수: 기본값, 나머지 매개변수 등 다양한 형태의 매개변수를 사용할 수 있습니다.
  • 함수 범위: 함수 내에서 선언된 변수는 함수 외부에서 접근할 수 없습니다.
  • 클로저: 함수와 그 함수가 생성된 렉시컬 환경의 결합입니다.
  • 재귀 함수: 자신을 호출하는 함수입니다.
  • 고차 함수: 함수를 인자로 받거나 함수를 반환하는 함수입니다.

자바스크립트 함수의 매개변수 심층 탐구

매개변수란 무엇인가?

함수에 데이터를 전달하는 데 사용되는 변수를 매개변수라고 합니다. 함수를 호출할 때 전달하는 값을 인수라고 하며, 이 인수는 함수 내부에서 매개변수에 할당되어 사용됩니다.

function greet(name) {
  console.log("안녕하세요, " + name + "님!");
}

greet("홍길동"); // name 매개변수에 "홍길동"이 할당됨

매개변수의 종류

  • 기본값 매개변수: 매개변수에 값이 전달되지 않을 경우 사용될 기본값을 설정할 수 있습니다.
    function greet(name = "익명") {
      console.log("안녕하세요, " + name + "님!");
    }
    
    greet(); // "안녕하세요, 익명님!" 출력
    
  • 나머지 매개변수: 여러 개의 인수를 배열로 받아 처리할 때 사용합니다.
    function sum(...numbers) {
      let result = 0;
      for (let num of numbers) {
        result += num;
      }
      return result;
    }
    
    console.log(sum(1, 2, 3, 4, 5)); // 15 출력
    

매개변수의 특징

  • 값에 의한 전달: 함수에 전달되는 값은 복사되어 매개변수에 할당됩니다. 따라서 함수 내부에서 매개변수의 값을 변경하더라도 원본 값에는 영향을 미치지 않습니다.
  • 유연성: 다양한 형태의 데이터를 매개변수로 전달할 수 있습니다. 숫자, 문자열, 배열, 객체 등 어떤 값이든 전달할 수 있습니다.
  • 가변 인수: 나머지 매개변수를 사용하면 함수에 전달되는 인수의 개수를 제한하지 않을 수 있습니다.

매개변수 사용 시 주의할 점

  • 매개변수의 순서: 함수를 호출할 때 매개변수의 순서를 정확히 지켜야 합니다.
  • 매개변수의 개수: 함수에 정의된 매개변수의 개수와 실제 전달되는 인수의 개수가 일치해야 합니다.
  • undefined 값: 매개변수에 값이 전달되지 않으면 undefined 값이 할당됩니다.

매개변수 활용 예시

  • 다양한 함수:
    • Math.max(): 가장 큰 값을 찾는 함수
    • Array.prototype.map(): 배열의 각 요소를 변환하는 함수
    • setTimeout(): 특정 시간 후에 함수를 실행하는 함수
  • 커스텀 함수:
    • 데이터 가공, 계산, DOM 조작 등 다양한 작업을 수행하는 함수

자바스크립트 함수 범위 (Scope) 심층 탐구

함수 범위란 무엇일까요?

함수 범위는 변수가 유효한 영역을 의미합니다. 즉, 어떤 변수에 접근할 수 있는지, 어디서부터 어디까지 변수를 사용할 수 있는지를 결정하는 규칙입니다. 자바스크립트에서는 **렉시컬 환경(Lexical Environment)**이라는 개념을 통해 함수 범위를 관리합니다.

렉시컬 환경이란?

렉시컬 환경은 변수와 함수 선언이 저장되는 공간입니다. 코드가 작성된 순서대로 렉시컬 환경이 생성되며, 각 함수는 자신만의 렉시컬 환경을 가지고 있습니다. 즉, 함수 내에서 선언된 변수는 그 함수의 렉시컬 환경에 저장되며, 다른 함수에서는 접근할 수 없습니다.

함수 범위의 종류

  1. 전역 범위 (Global Scope):
    • 모든 코드에서 접근 가능한 변수가 저장되는 영역입니다.
    • 전역 변수는 주의해서 사용해야 합니다. 전역 변수를 너무 많이 사용하면 변수 간 충돌이 발생할 가능성이 높아지고, 코드 관리가 어려워질 수 있습니다.
  2. 지역 범위 (Local Scope):
    • 함수 내에서 선언된 변수가 저장되는 영역입니다.
    • 함수 내에서만 유효하며, 함수 외부에서는 접근할 수 없습니다.
  3. 블록 범위 (Block Scope):
    • ES6부터 도입된 개념으로, letconst 키워드로 선언된 변수는 블록({}) 내에서만 유효합니다.
    • var 키워드로 선언된 변수는 함수 범위를 따르므로 주의해야 합니다.

함수 범위 예시

// 전역 변수
let globalVar = "전역 변수";

function outerFunction() {
  let outerVar = "외부 함수 변수";

  function innerFunction() {
    let innerVar = "내부 함수 변수";
    console.log(globalVar); // 접근 가능
    console.log(outerVar); // 접근 가능
    console.log(innerVar); // 접근 가능
  }

  innerFunction();
  console.log(innerVar); // 접근 불가
}

outerFunction();
console.log(outerVar); // 접근 불가

클로저 (Closure)

  • 함수와 그 함수가 생성된 렉시컬 환경의 결합을 클로저라고 합니다.
  • 내부 함수는 외부 함수의 렉시컬 환경에 접근할 수 있기 때문에 클로저가 발생합니다.
  • 클로저는 자바스크립트의 강력한 기능 중 하나이며, 다양한 패턴에서 활용됩니다.

함수 범위를 이해해야 하는 이유

  • 변수 충돌 방지: 함수 범위를 명확히 함으로써 변수 이름 충돌을 방지하고 코드 가독성을 높일 수 있습니다.
  • 메모리 관리: 필요 없는 변수를 빠르게 해제하여 메모리 누수를 방지할 수 있습니다.
  • 클로저 활용: 클로저를 이해하면 더욱 유연하고 복잡한 프로그램을 작성할 수 있습니다.

정리

  • 함수 범위는 변수의 유효 범위를 결정합니다.
  • 렉시컬 환경은 변수와 함수 선언이 저장되는 공간입니다.
  • 전역 범위, 지역 범위, 블록 범위가 있습니다.
  • 클로저는 함수와 렉시컬 환경의 결합입니다.

재귀 함수: 자기 자신을 호출하는 함수

재귀 함수란 무엇인가요?

재귀 함수는 함수 내부에서 자기 자신을 호출하는 함수를 의미합니다. 마치 거울이 서로를 비추듯이, 함수가 자기 자신을 다시 실행하는 형태입니다.

function factorial(n) {
  if (n === 0) {
    return 1;
  } else {
    return n * factorial(n - 1);
  }
}

console.log(factorial(5)); // 120

위 예시에서 factorial 함수는 자기 자신을 호출하여 n! (n의 팩토리얼)을 계산합니다.

재귀 함수의 작동 원리

  1. 기저 사례 (Base Case): 재귀가 종료되는 조건을 설정합니다. 위 예시에서는 n이 0일 때 1을 반환하며 재귀를 멈춥니다.
  2. 재귀 호출 (Recursive Case): 기저 사례가 아닐 때, 함수는 자기 자신을 호출하며 문제를 더 작은 단위로 분해합니다.
  3. 호출 스택 (Call Stack): 함수 호출은 스택 자료구조에 쌓입니다. 각 호출마다 새로운 스택 프레임이 생성되어 지역 변수와 매개변수를 저장합니다.
  4. 반환: 기저 사례에 도달하거나 모든 재귀 호출이 완료되면 스택 프레임이 해제되면서 결과가 반환됩니다.

재귀 함수의 장점

  • 복잡한 문제를 간결하게 해결: 특히 재귀적인 구조를 가진 문제 (예: 트리 순회, 팩토리얼 계산)를 해결하는 데 효과적입니다.
  • 코드 가독성 향상: 반복적인 작업을 재귀 함수로 표현하면 코드가 더 직관적이고 이해하기 쉬워집니다.

재귀 함수의 단점

  • 성능 저하: 과도한 재귀 호출은 스택 오버플로우를 발생시킬 수 있으며, 반복문에 비해 성능이 저하될 수 있습니다.
  • 디버깅 어려움: 재귀 호출이 깊어질수록 코드를 추적하기 어려울 수 있습니다.

재귀 함수 사용 시 주의할 점

  • 기저 사례 명확하게 설정: 반드시 종료 조건을 설정해야 무한 루프에 빠지지 않습니다.
  • 호출 깊이 제한: 스택 오버플로우를 방지하기 위해 호출 깊이를 제한하는 방법을 고려해야 합니다.
  • 반복문과의 비교: 모든 문제를 재귀 함수로 해결해야 하는 것은 아닙니다. 문제의 특성에 맞는 알고리즘을 선택해야 합니다.

재귀 함수 활용 예시

  • 팩토리얼 계산: 위에서 예시로 들었던 factorial 함수
  • 피보나치 수열: 이전 두 항의 합으로 다음 항을 구하는 수열
  • 트리 순회: 이진 트리, 일반 트리 등의 노드를 순회하는 알고리즘
  • 분할 정복 알고리즘: 문제를 작은 문제로 나누어 해결하는 알고리즘 (퀵 정렬, 병합 정렬 등)

고차 함수 (Higher-Order Function) 심층 탐구

고차 함수란 무엇일까요?

고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수를 의미합니다. 즉, 함수를 데이터처럼 다루는 함수라고 생각하면 됩니다. 자바스크립트에서는 함수가 일급 객체이기 때문에 이러한 고차 함수를 자연스럽게 사용할 수 있습니다.

핵심 특징:

  • 함수를 인자로 받음: 다른 함수를 인자로 전달하여 다양한 동작을 수행할 수 있습니다.
  • 함수를 반환: 새로운 함수를 생성하여 반환할 수 있습니다.
  • 함수형 프로그래밍의 기반: 코드를 더욱 추상화하고 재사용성을 높여 함수형 프로그래밍 스타일을 구현하는 데 중요한 역할을 합니다.

왜 고차 함수를 사용할까요?

  • 코드 재사용성 증가: 공통적인 로직을 함수로 추출하여 여러 곳에서 재사용할 수 있습니다.
  • 코드 가독성 향상: 복잡한 로직을 작은 함수들로 분리하여 코드를 더 명확하게 만들 수 있습니다.
  • 추상화: 구체적인 구현 로직을 숨기고 함수의 목적만 명확하게 드러낼 수 있습니다.
  • 함수형 프로그래밍: 순수 함수, 불변성 등 함수형 프로그래밍의 원리를 적용하여 코드를 더욱 안정적이고 예측 가능하게 만들 수 있습니다.

고차 함수의 종류와 예시

  • map: 배열의 각 요소를 변환하여 새로운 배열을 생성합니다.
    const numbers = [1, 2, 3];
    const doubled = numbers.map(x => x * 2); // [2, 4, 6]
    
  • filter: 주어진 조건을 만족하는 요소만 추출하여 새로운 배열을 생성합니다.
    const numbers = [1, 2, 3, 4, 5];
    const evenNumbers = numbers.filter(x => x % 2 === 0); // [2, 4]
    
  • reduce: 배열의 모든 요소를 하나의 값으로 축소합니다.
    const numbers = [1, 2, 3];
    const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0); // 6
    
  • forEach: 배열의 각 요소에 대해 특정 작업을 수행합니다.
    const numbers = [1, 2, 3];
    numbers.forEach(x => console.log(x)); // 1, 2, 3 출력
    
  • find: 주어진 조건을 만족하는 첫 번째 요소를 찾습니다.
    const numbers = [1, 2, 3, 4, 5];
    const found = numbers.find(x => x > 3); // 4
    

고차 함수를 직접 만들기

function map(array, callback) {
  const result = [];
  for (let i = 0; i < array.length; i++) {
    result.push(callback(array[i]));
  }
  return result;
}

고차 함수의 활용 예시

  • 이벤트 핸들러: 버튼 클릭, 마우스 이동 등의 이벤트 발생 시 실행할 함수를 인자로 전달합니다.
  • 데이터 가공: 배열 데이터를 필터링, 변환, 축소하는 등 다양한 작업을 수행합니다.
  • 비동기 처리: Promise, async/await 등 비동기 처리와 함께 사용하여 복잡한 비동기 로직을 간결하게 표현합니다.
  • 커링: 함수를 부분적으로 적용하여 새로운 함수를 생성하는 기법입니다.

 

728x90