Web Development/JavaScript

함수의 정의와 호출

newclass 2025. 3. 30. 22:15

함수는 JavaScript에서 코드를 구조화하고 재사용하는 핵심 개념입니다. 이 챕터에서는 함수의 정의 방법, 매개변수와 반환값 처리, 그리고 변수의 스코프와 클로저에 대해 알아보겠습니다.

함수의 정의와 호출

JavaScript에서 함수를 정의하는 여러 방법과 함수를 호출하는 방법에 대해 살펴보겠습니다.

함수 선언문

가장 기본적인 함수 정의 방법으로, function 키워드와 함수 이름을 사용합니다.

// 기본 함수 선언
function greet() {
  console.log("안녕하세요!");
}

// 함수 호출
greet(); // "안녕하세요!" 출력

// 매개변수를 가진 함수
function greetUser(userName) {
  console.log(`안녕하세요, ${userName}님!`);
}

greetUser("홍길동"); // "안녕하세요, 홍길동님!" 출력
greetUser(); // "안녕하세요, undefined님!" 출력

// 기본 매개변수(ES6)
function greetWithDefault(userName = "게스트") {
  console.log(`안녕하세요, ${userName}님!`);
}

greetWithDefault(); // "안녕하세요, 게스트님!" 출력
greetWithDefault("김철수"); // "안녕하세요, 김철수님!" 출력

// 반환값을 가진 함수
function sum(a, b) {
  return a + b;
}

const result = sum(5, 3);
console.log(result); // 8 출력

// 여러 값 반환 (배열 사용)
function getMinMax(numbers) {
  const min = Math.min(...numbers);
  const max = Math.max(...numbers);
  return [min, max];
}

const [minValue, maxValue] = getMinMax([5, 2, 9, 1, 7]);
console.log(minValue, maxValue); // 1 9 출력

// 여러 값 반환 (객체 사용)
function getUserInfo() {
  return {
    name: "홍길동",
    age: 25,
    isAdmin: false
  };
}

const { name, age } = getUserInfo();
console.log(name, age); // "홍길동" 25 출력

함수 표현식

함수를 변수에 할당하는 방식으로, 익명 함수(anonymous function)를 만들 수 있습니다.

// 기본 함수 표현식
const greet = function() {
  console.log("안녕하세요!");
};

greet(); // "안녕하세요!" 출력

// 명명된 함수 표현식
const factorial = function calc(n) {
  if (n <= 1) return 1;
  return n * calc(n - 1); // 함수 내부에서 calc 이름으로 재귀 호출 가능
};

console.log(factorial(5)); // 120 출력
// console.log(calc(5)); // 오류: calc is not defined

// 함수를 다른 함수의 인자로 전달
function executeFunction(func) {
  console.log("함수 실행:");
  func();
}

executeFunction(function() {
  console.log("전달된 함수 내부");
});
// 출력:
// 함수 실행:
// 전달된 함수 내부

// 함수를 다른 함수의 반환값으로 사용
function createMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 10 출력
console.log(triple(5)); // 15 출력

함수 선언문 vs 함수 표현식

함수 선언문과 함수 표현식의 주요 차이점은 호이스팅(hoisting) 동작에 있습니다.

// 함수 선언문은 호이스팅됨
sayHello(); // "안녕하세요!" 출력 (오류 없음)

function sayHello() {
  console.log("안녕하세요!");
}

// 함수 표현식은 변수 선언만 호이스팅됨
// sayHi(); // 오류: sayHi is not a function

const sayHi = function() {
  console.log("안녕하세요!");
};

sayHi(); // "안녕하세요!" 출력

화살표 함수(Arrow Function)

ES6에서 도입된 함수 표현의 간결한 형태로, 특히 짧은 함수 작성에 유용합니다.

// 기본 화살표 함수
const greet = () => {
  console.log("안녕하세요!");
};

greet(); // "안녕하세요!" 출력

// 매개변수가 하나인 경우 괄호 생략 가능
const greetUser = name => {
  console.log(`안녕하세요, ${name}님!`);
};

greetUser("홍길동"); // "안녕하세요, 홍길동님!" 출력

// 본문이 한 줄인 경우 중괄호와 return 생략 가능
const double = x => x * 2;
console.log(double(5)); // 10 출력

// 객체 반환 시 괄호로 감싸야 함
const createUser = (name, age) => ({ name, age });
console.log(createUser("홍길동", 25)); // { name: "홍길동", age: 25 } 출력

// 여러 매개변수
const sum = (a, b) => a + b;
console.log(sum(3, 4)); // 7 출력

// 화살표 함수는 this 바인딩이 다름
const user = {
  name: "홍길동",
  sayHello: function() {
    console.log(`안녕하세요, ${this.name}입니다!`);
  },
  sayHelloArrow: () => {
    console.log(`안녕하세요, ${this.name}입니다!`);
  }
};

user.sayHello(); // "안녕하세요, 홍길동입니다!" 출력
user.sayHelloArrow(); // "안녕하세요, undefined입니다!" 출력 (this가 전역 객체를 가리킴)

화살표 함수의 특징:

  • 더 짧고 간결한 문법
  • this가 함수를 정의한 시점의 상위 스코프(렉시컬 스코프)에 바인딩됨
  • arguments 객체 없음
  • 생성자로 사용할 수 없음 (new 연산자와 함께 사용 불가)
  • yield 키워드 사용 불가(제너레이터 함수로 사용 불가)

매개변수와 반환값

함수의 입력(매개변수)과 출력(반환값)을 처리하는 다양한 방법을 알아보겠습니다.

매개변수 처리

// 기본 매개변수(ES6)
function greet(name = "게스트", greeting = "안녕하세요") {
  console.log(`${greeting}, ${name}님!`);
}

greet(); // "안녕하세요, 게스트님!" 출력
greet("홍길동"); // "안녕하세요, 홍길동님!" 출력
greet("홍길동", "반갑습니다"); // "반갑습니다, 홍길동님!" 출력

// 나머지 매개변수(Rest Parameters)
function sum(...numbers) {
  return numbers.reduce((total, current) => total + current, 0);
}

console.log(sum(1, 2)); // 3 출력
console.log(sum(1, 2, 3, 4, 5)); // 15 출력

// 나머지 매개변수와 일반 매개변수 혼합
function introduce(name, age, ...hobbies) {
  console.log(`이름: ${name}, 나이: ${age}세`);
  if (hobbies.length > 0) {
    console.log(`취미: ${hobbies.join(', ')}`);
  }
}

introduce("홍길동", 25, "독서", "여행", "요리");
// 출력:
// 이름: 홍길동, 나이: 25세
// 취미: 독서, 여행, 요리

// arguments 객체 (레거시 방식)
function oldSum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

console.log(oldSum(1, 2, 3)); // 6 출력

// 매개변수 기본값 활용 복잡한 예제
function createUser(name, { age = 20, role = "사용자", active = true } = {}) {
  return {
    name,
    age,
    role,
    active
  };
}

console.log(createUser("홍길동")); // { name: "홍길동", age: 20, role: "사용자", active: true }
console.log(createUser("김철수", { age: 30, role: "관리자" })); // { name: "김철수", age: 30, role: "관리자", active: true }

반환값 처리

// 값 반환
function add(a, b) {
  return a + b;
}

// 여러 값 반환 (객체 사용)
function divideWithRemainder(a, b) {
  if (b === 0) {
    return { error: "0으로 나눌 수 없습니다." };
  }
  return {
    quotient: Math.floor(a / b),
    remainder: a % b
  };
}

const result = divideWithRemainder(10, 3);
console.log(result); // { quotient: 3, remainder: 1 }

// 조건부 반환
function findUser(users, id) {
  const user = users.find(user => user.id === id);
  if (!user) {
    return null; // 사용자를 찾지 못한 경우
  }
  return user;
}

// 함수 반환
function makeCounter(startFrom = 0, step = 1) {
  let count = startFrom;
  
  return function() {
    const current = count;
    count += step;
    return current;
  };
}

const counter = makeCounter(1, 2);
console.log(counter()); // 1 출력
console.log(counter()); // 3 출력
console.log(counter()); // 5 출력

// Promise 반환 (비동기 함수)
function fetchUserData(userId) {
  return new Promise((resolve, reject) => {
    // 실제로는 API 호출 등의 비동기 작업
    setTimeout(() => {
      if (userId > 0) {
        resolve({ id: userId, name: "사용자" + userId });
      } else {
        reject(new Error("유효하지 않은 사용자 ID"));
      }
    }, 1000);
  });
}

// 반환값 없는 함수 (암묵적으로 undefined 반환)
function logMessage(message) {
  console.log(message);
  // return 문이 없으면 undefined 반환
}

const result2 = logMessage("테스트");
console.log(result2); // undefined 출력