하나의 특별한 목적의 작업을 수행하도록 설계된 독립적인 블록이다. 필요할 때마다 호출해서 해당 작업을 반복해서 수행할 수 있다. 함수는 재사용 가능한 코드 조각을 작성하고, 프로그램을 조직화, 코드의 가독성을 향상시킨다.
함수 정의
함수 선언
함수 선언은 function
키워드를 사용하여 함수를 정의하는 방식이다.
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet('Alice')); // Hello, Alice!
예제
서버 로그 기록을 관리할 필요가 있을 때, 간단하게 로그를 남길 수 있는 함수를 만들 수 있다.
function logMessage(level, message) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [${level}] ${message}`);
}
// 사용 예제
logMessage('INFO', 'Server started'); // [2024-06-17T12:00:00.000Z] [INFO] Server started
logMessage('ERROR', 'Failed to connect to database'); // [2024-06-17T12:01:00.000Z] [ERROR] Failed to connect to database
함수 표현식
함수 표현식은 변수에 익명 함수를 할당하는 방식이다.
const greet = function(name) {
return `Hello, ${name}!`;
};
console.log(greet('Bob')); // Hello, Bob!
화살표 함수
화살표 함수는 간결한 문법을 제공하며, function
키둬드를 제공하지 않는다. 특히 콜백 함수로 자주 사용된다.
const greet = (name) => {
return `Hello, ${name}!`;
};
console.log(greet('Charlie')); // Hello, Charlie!
// 짧은 문법 (중괄호와 return 생략)
const greetShort = name => `Hello, ${name}!`;
console.log(greetShort('Dave')); // Hello, Dave!
즉시 실행 함수
IIFE(Immediately Invoked Function Expression)는 정의되자마자 즉시 실행되는 함수이다.
(function() {
console.log('This is an IIFE');
})(); // This is an IIFE
함수 매개변수
함수를 호출할 때 인수(argument)로 전달된 값을 함수 내부에서 사용할 수 있게 해주는 변수이다.
기본 매개변수
기본 매개변수를 사용하면 함수 호출 시 인수가 전달되지 않았을 때 기본값을 사용할 수 있다.
function greet(name = 'Guest') {
return `Hello, ${name}!`;
}
console.log(greet()); // Hello, Guest!
console.log(greet('Eve')); // Hello, Eve!
나머지 매개변수
나머지 매개변수를 사용하면 함수에 전달된 모든 인수를 배열로 받을 수 있다.
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4)); // 10
예시
API 호출 함수다. 기본 매개변수를 사용하여 호출 시 특정 매개변수가 전달되지 않았을 때 기본값을 사용하도록 했다.
function fetchData(url, method = 'GET') {
return fetch(url, { method })
.then(response => response.json())
.catch(error => console.error('Error:', error));
}
// 사용 예제
fetchData('https://api.example.com/data'); // GET 메서드로 호출
fetchData('https://api.example.com/data', 'POST'); // POST 메서드로 호출
함수 반환 값
함수는 기본적으로 undefined
를 반환한다. return
키워드를 사용하여 값을 반환할 수 있다. 즉, 함수를 호출했을 때 결과값을 반환한다. 그리고 return
문이 실행되면 코드는 강제 종료된다.
function addNum(a, b) {
return a + b;
}
const num = addNum(7, 37); // 손흥민 넘버💙, 반더벤 넘버💙
console.log(num); // 44
위 코드에서 return
문은 addNum
함수 내에서 사용되었고, 이 함수는 두 개의 매개변수 a
와 b
를 받는다.
- 함수
addNum
을 호출한다. 이 때,a
에는 7,b
에는 37이 전달된다. - 함수 내부에서
return
문이 실행되고,a
와b
를 더한 결과가 반환된다. - 함수가 값을 반환. 이 반환값을 변수
num
에 할당한다. addNum
의 반환값인 37이 출력된다.
함수 특징
함수는 객체
JavaScript의 함수는 일급 객체로, 변수나 배열에 할당되거나 다른 함수의 인수로 전달되거나 함수에서 반환될 수 있다.
const sayHello = name => `Hello, ${name}!`;
function greet(fn, name) {
console.log(fn(name));
}
greet(sayHello, 'Frank'); // Hello, Frank!
클로저
클로저는 함수가 생성될 당시의 렉시컬 환경을 기억하여, 함수 외부에서 정의된 변수에 접근할 수 있는 기능이다.
function makeCounter() {
let count = 0;
return function() {
count += 1;
return count;
};
}
const counter = makeCounter();
console.log(counter()); // 1
console.log(counter()); // 2
고차 함수
고차 함수는 함수를 인수로 받거나 함수를 반환하는 함수이다.
function repeat(n, action) {
for (let i = 0; i < n; i++) {
action(i);
}
}
repeat(3, console.log);
// 0
// 1
// 2
재귀
함수는 자신을 호출하여 재귀적으로 동작할 수 있다.
function factorial(n) {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
함수 사용
객체 메서드로 함수 선언
함수는 객체의 메서드로 정의될 수 있다. 관련된 함수를 논리적으로 그룹화하고 싶을 때 사용한다. 예를 들어, 유틸리티 함수들을 하나의 객체에 모아 관리할 때 유용하다.
const utils = {
greet(name) {
return `Hello, ${name}!`;
},
add(a, b) {
return a + b;
}
};
console.log(utils.greet('Alice')); // Hello, Alice!
console.log(utils.add(3, 4)); // 7
클래스 내에서 메서드 정의
객체 지향 설계를 통해 객체의 상태를 관리하고 객체의 행동을 정의할 수 있다.
class Circle {
constructor(radius) {
this.radius = radius;
}
calculateArea () {
return Math.PI * this.radius * this.radius;
}
// 화살표 함수를 사용하여 메서드를 정의
calculateArea = () => Math.PI * this.radius * this.radius;
}
const circle = new Circle(5);
console.log(circle.calculateArea()); // 78.53981633974483 출력
콜백 함수
콜백 함수는 다른 함수에 인수로 전달되는 함수이다.
function fetchData(callback) {
setTimeout(() => {
callback('Data fetched');
}, 1000);
}
fetchData(console.log); // 1초 후 출력: Data fetched
클래스와 함수 선언식 결정
다양한 프로젝트를 하면서 함수와 클래스를 활용한 여러 방법을 경험했다. 언제 클래스 내 메서드를 사용하고, 언제 함수 선언식을 사용하는 것이 좋은지 간략하게 정리해 보겠다.
클래스 내 메서드
사례: API 통신 모듈
API 통신 모듈을 개발할 때, 각 API 요청마다 공통적인 로직이 많았다. 이럴 때는 클래스를 사용하여 공통 로직을 한 곳에 모으고, 필요에 따라 메서드를 확장하는 방식이 유리했다.
class ApiService {
constructor(baseURL) {
this.baseURL = baseURL;
}
async get(endpoint) {
const response = await fetch(`${this.baseURL}${endpoint}`);
return response.json();
}
async post(endpoint, data) {
const response = await fetch(`${this.baseURL}${endpoint}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
return response.json();
}
}
// 사용 예제
const api = new ApiService('https://api.example.com');
api.get('/users').then(data => console.log(data));
api.post('/users', { name: 'Charlie' }).then(data => console.log(data));
함수 선언식
사례: 데이터 유효성 검사
유효성 검사는 독립적인 기능으로, 특정 객체나 클래스에 종속될 필요가 없다. 이럴 때 함수 선언식을 사용하여 간단하게 필요한 기능을 구현했다.
function validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
function validatePassword(password) {
return password.length >= 8;
}
// 사용 예제
const email = 'test@example.com';
const password = 'securepassword123';
console.log(validateEmail(email)); // true
console.log(validatePassword(password)); // true
정리
- 함수 정의 방법에는 다양한 접근 방식이 있다.
- 각각의 상황에 맞게 선택하여 사용하면 된다.
- 프로젝트의 요구사항과 코드의 구조에 따라 다양한 함수 정의 방법을 조합하여 사용할 수 있다.