안녕하세요! 오늘은 자바스크립트의 핵심 개념 중 하나인 함수에 대해 완전히 정복해보겠습니다.
함수 부분은 공부해야 할 내용들이 많이 있어 긴글 인점 양해 바랍니다!
모던 자바스크립트 입문 외에 다른곳에서도 참고해서 작성된 내용이 있습니다.
📌 목차
- 8.1 함수의 정의하기
- 8.2 함수 호출하기
- 8.3 함수의 인수
- 8.4 재귀 함수
- 8.5 프로그램의 평가와 실행 과정
- 8.6 클로저
- 8.7 이름 공간 (생략)
- 8.8 객체로서의 함수
- 8.9 고차 함수
- 8.10 콜백함수
- 8.11 ECMAScript 6부터 추가된 함수의 기능
📝 함수의 정의하기
함수를 정의하는 방법은 네 가지입니다.
1️⃣ 함수 선언문(Function Declaration)
function square(x) {
return x * x;
}
2️⃣ 함수 표현식(Function Expression)
// 익명 함수 표현식
let square = function(x) {
return x * x;
};
// 기명 함수 표현식
let factorial = function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1);
};
3️⃣ Function 생성자로 정의하는 방법
let square = new Function("x", "return x * x");
// 여러 매개변수가 있는 경우
let add = new Function("a", "b", "return a + b");
⚠️ 주의: Function 생성자는 성능상 권장되지 않으며, 보안 이슈가 있을 수 있습니다.
4️⃣ 화살표 함수 표현식(Arrow Function) - ES6+
// 기본 형태
let square = x => x * x;
// 매개변수가 여러 개인 경우
let add = (a, b) => a + b;
// 함수 본문이 여러 줄인 경우
let multiply = (a, b) => {
console.log(`${a} × ${b} 계산 중...`);
return a * b;
};
// 객체를 반환하는 경우 (괄호 필요)
let createPerson = (name, age) => ({ name, age });
📝 함수 호출하기
1️⃣ 함수 호출
함수의 참조가 저장된 변수 뒤에 호출 연산자인 ()를 붙여서 함수를 호출합니다.
function greet(name) {
return `안녕하세요, ${name}님!`;
}
let message = greet("홍길동");
console.log(message); // "안녕하세요, 홍길동님!"
2️⃣ 메서드 호출
객체의 프로퍼티에 저장된 값이 함수 타입일 때는 그 프로퍼티를 메서드라고 부릅니다.
let person = {
name: "김철수",
greet: function() {
return `안녕하세요, 저는 ${this.name}입니다.`;
},
// ES6 축약 문법
introduce() {
return `제 이름은 ${this.name}입니다.`;
}
};
console.log(person.greet()); // "안녕하세요, 저는 김철수입니다."
console.log(person.introduce()); // "제 이름은 김철수입니다."
3️⃣ 생성자 호출
함수 또는 메서드를 호출할 때 함수의 참조를 저장한 변수 앞에 new 키워드를 추가하면 함수가 생성자로 동작합니다.
function Person(name, age) {
this.name = name;
this.age = age;
this.introduce = function() {
return `저는 ${this.name}이고, ${this.age}살입니다.`;
};
}
let person1 = new Person("이영희", 25);
console.log(person1.introduce()); // "저는 이영희이고, 25살입니다."
4️⃣ call, apply, bind를 사용한 간접 호출
함수의 call, apply, bind 메서드를 사용하면 함수를 간접적으로 호출할 수 있습니다.
function introduce(greeting, punctuation) {
return `${greeting}, 저는 ${this.name}입니다${punctuation}`;
}
let person = { name: "박민수" };
// call: 인수를 개별적으로 전달
console.log(introduce.call(person, "안녕하세요", "!"));
// "안녕하세요, 저는 박민수입니다!"
// apply: 인수를 배열로 전달
console.log(introduce.apply(person, ["반갑습니다", "."]));
// "반갑습니다, 저는 박민수입니다."
// bind: 새로운 함수를 생성 (나중에 호출)
let boundIntroduce = introduce.bind(person, "어서오세요");
console.log(boundIntroduce("~")); // "어서오세요, 저는 박민수입니다~"
📝 함수의 인수
인수의 생략
함수 정의에서 선언된 매개변수 개수보다 인수를 적게 전달하면, 생략된 매개변수는 undefined가 됩니다.
function greet(firstName, lastName) {
console.log(`안녕하세요, ${firstName} ${lastName}님!`);
}
greet("홍"); // "안녕하세요, 홍 undefined님!"
기본값 매개변수 (ES6+)
매개변수에 기본값을 설정할 수 있습니다.
function greet(firstName, lastName = "님") {
console.log(`안녕하세요, ${firstName} ${lastName}!`);
}
greet("홍길동"); // "안녕하세요, 홍길동 님!"
greet("김철수", "씨"); // "안녕하세요, 김철수 씨!"
가변 길이 인수 목록
function sum() {
let total = 0;
for(let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// ES6+ 나머지 매개변수 사용
function sumES6(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sumES6(1, 2, 3, 4, 5)); // 15
📝 재귀 함수
재귀 함수는 자기 자신을 호출하는 함수입니다.
재귀 함수의 기본
function fact(n) {
if(n <= 1) return 1;
return n*fact(n-1);
}
fact(5); // 120
📝 프로그램의 평가와 실행 과정
실행 컨텍스트(Execution Context)
자바스크립트 엔진은 실행 가능한 코드를 만나면 그 코드를 평가해서 실행 문맥으로 만듭니다.
실행 가능한 코드의 유형은:
- 전역 코드
- 함수 코드
- eval 코드
자바스크립트 엔진이 실행 가능한 코드의 유형을 분류하는 이유는 실행 문맥을 초기화하는 환경과 과정이 다르기 때문이다
this값
함수가 호출되어 실행되는 시점에 this 값이 결정됩니다.
이 this 값은 '함수가 호출되었을 때 그 함수가 속해 있던 객체의 참조'이며 실행 문맥의 디스 바인딩 컴포넌트가 참조하는 객체입니다.
1️⃣ 최상위 레벨 코드의 this - 전역 객체 (window)
console.log(this); // Window 객체 (브라우저 환경)
console.log(this === window); // true
// 전역 변수는 window의 속성이 됨
var globalVar = "전역변수";
console.log(this.globalVar); // "전역변수"
2️⃣ 이벤트 처리기 안에 있는 this - 이벤트 대상 요소
const button = document.querySelector('button');
button.addEventListener('click', function() {
console.log(this); // <button> 요소
console.log(this.textContent); // 버튼의 텍스트 내용
this.style.color = 'red'; // 클릭한 버튼의 글자색 변경
});
// 화살표 함수는 상위 스코프의 this를 사용
button.addEventListener('click', () => {
console.log(this); // Window 객체 (상위 스코프)
});
3️⃣ 생성자 함수 안에 있는 this - 생성된 인스턴스 객체
function Car(brand, model) {
this.brand = brand; // this = 새로 생성될 객체
this.model = model;
this.start = function() {
console.log(`${this.brand} ${this.model} 시동 켜짐!`);
};
}
const myCar = new Car('현대', '아반떼');
console.log(myCar.brand); // "현대"
myCar.start(); // "현대 아반떼 시동 켜짐!"
4️⃣ 생성자의 prototype 메서드 안에 있는 this - 생성된 인스턴스 객체
function Person(name) {
this.name = name;
}
Person.prototype.introduce = function() {
console.log(`안녕하세요, ${this.name}입니다!`);
// this = 메서드를 호출한 인스턴스 객체
};
const person1 = new Person('김개발');
const person2 = new Person('이자바');
person1.introduce(); // "안녕하세요, 김개발입니다!"
person2.introduce(); // "안녕하세요, 이자바입니다!"
5️⃣ 직접 호출한 함수 안에 있는 this - 전역 객체 (strict mode에서는 undefined)
function normalFunction() {
console.log(this); // Window 객체 (strict mode에서는 undefined)
}
const obj = {
method: function() {
console.log(this); // obj 객체
function innerFunction() {
console.log(this); // Window 객체 (내부 함수는 전역)
}
innerFunction();
}
};
normalFunction(); // 직접 호출
obj.method(); // 객체의 메서드로 호출
6️⃣ apply와 call , bind 메서드로 호출한 함수 안에 this - 첫 번째 인수로 전달한 객체
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const person = { name: '박자바' };
const company = { name: '테크기업' };
// call: 인수를 개별적으로 전달
greet.call(person, '안녕하세요', '!'); // "안녕하세요, 박자바!"
greet.call(company, '환영합니다', '.'); // "환영합니다, 테크기업."
// apply: 인수를 배열로 전달
greet.apply(person, ['반갑습니다', '~']); // "반갑습니다, 박자바~"
// bind: this가 고정된 새 함수 생성
const boundGreet = greet.bind(person);
boundGreet('좋은 하루', '♪'); // "좋은 하루, 박자바♪"
📝 클로저
클로저를 프로그래밍 언어적인 관점에서 설명하면 같은 동작을 하는 함수와 그 기능을 구현한 자료 구조의 모음이라고 할 수 있습니다
자기 자신이 정의된 환경에서 함수 안에 있는 자유 변수의 식별자 결정을 실행한다.
기본 클로저
function outerFunction(x) {
// 외부 함수의 변수
function innerFunction(y) {
// 내부 함수에서 외부 함수의 변수에 접근
return x + y;
}
return innerFunction; // 내부 함수를 반환
}
let addFive = outerFunction(5);
console.log(addFive(3)); // 8 (5 + 3)
📝 객체로서의 함수
자바스크립트에서 함수는 일급 객체(First-class Object)입니다.
함수의 프로퍼티와 메서드
function myFunction(a, b) {
return a + b;
}
// 함수 자체의 프로퍼티
console.log(myFunction.name); // "myFunction"
console.log(myFunction.length); // 2 (매개변수 개수)
// 함수에 사용자 정의 프로퍼티 추가
myFunction.description = "두 수를 더하는 함수";
myFunction.version = "1.0";
console.log(myFunction.description); // "두 수를 더하는 함수"
함수의 프로퍼티
프로퍼티 이름 | 설명 |
caller | 현재 실행 중인 함수를 호출한 함수 |
length | 함수의 인자 개수 |
name | 함수를 표시할 때 사용하는 이름 |
prototype | 프로토타입 객체의 참조 |
Function.prototype의 프로퍼티
프로퍼티 이름 | 설명 |
apply() | 선택한 this와 인수를 사용하여 함수를 호출한다. 인수는 배열 객체이다. |
bind() | 선택한 this와 인수를 적용한 새로운 함수를 반환한다 |
call() | 선택한 this와 인수를 사용하여 함수를 호출한다. 인수는 쉼표로 구분한 값이다. |
constructor | Function 생성자의 참조 |
toString() | 함수의 소스 코드를 문자열로 만들어 반환한다 |
📝고차 함수
고차 함수란? 함수를 다루는 함수입니다!
- 함수를 받아서 사용하거나
- 함수를 만들어서 돌려주는 함수
1️⃣ 함수를 만들어 주는 함수
// 곱하기 함수를 만드는 공장
function makeMultiplier(num) {
return function(x) {
return x * num;
};
}
// 2배, 3배 함수 만들기
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
console.log(double(5)); // 10 (5 × 2)
console.log(triple(4)); // 12 (4 × 3)
2️⃣ 함수를 받아서 사용하는 함수
// 계산기 함수
function calculator(a, b, operation) {
return operation(a, b);
}
// 더하기, 빼기 함수
const add = (x, y) => x + y;
const subtract = (x, y) => x - y;
console.log(calculator(10, 5, add)); // 15
console.log(calculator(10, 5, subtract)); // 5
3️⃣ 배열에서 자주 쓰는 고차 함수들
const numbers = [1, 2, 3, 4, 5];
// map: 모든 요소를 바꾸기
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter: 조건에 맞는 것만 골라내기
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4]
// 한 번에 여러 작업하기
const result = numbers
.filter(num => num > 2) // 2보다 큰 수만
.map(num => num * 10); // 10배로 만들기
console.log(result); // [30, 40, 50]
4️⃣ 실용적인 예시
// 인사말 만들기
function createGreeting(greeting) {
return function(name) {
return `${greeting}, ${name}님!`;
};
}
const sayHello = createGreeting('안녕하세요');
const sayGoodbye = createGreeting('안녕히 가세요');
console.log(sayHello('김철수')); // "안녕하세요, 김철수님!"
console.log(sayGoodbye('이영희')); // "안녕히 가세요, 이영희님!"
💡 왜 고차 함수를 쓸까요?
✅ 코드 재사용: 비슷한 함수를 여러 번 만들 필요 없음
✅ 깔끔한 코드: 복잡한 로직을 간단하게 표현
✅ 유연함: 상황에 맞는 함수를 동적으로 생성
핵심: 고차 함수는 함수를 재료로 사용해서 새로운 함수를 만들거나, 함수에게 일을 시키는 함수입니다!
📝 콜백함수
콜백 함수는 다른 함수에 인수로 전달되어 나중에 호출되는 함수입니다.
기본 콜백 함수
function processUserInput(callback) {
let name = "홍길동";
let age = 25;
// 콜백 함수 호출
callback(name, age);
}
function greetUser(name, age) {
console.log(`안녕하세요, ${name}님! ${age}세시군요.`);
}
function showUserInfo(name, age) {
console.log(`사용자 정보: 이름=${name}, 나이=${age}`);
}
// 다른 콜백 함수 사용
processUserInput(greetUser); // "안녕하세요, 홍길동님! 25세시군요."
processUserInput(showUserInfo); // "사용자 정보: 이름=홍길동, 나이=25"
📝 ES6+ 함수의 새로운 기능들
1️⃣ 기본 매개변수 (Default Parameters)
// 옛날 방식
function greet(name, msg) {
msg = msg || "안녕하세요";
return msg + ", " + name;
}
// 새로운 방식
function greet(name, msg = "안녕하세요") {
return `${msg}, ${name}`;
}
console.log(greet("홍길동")); // "안녕하세요, 홍길동"
console.log(greet("김철수", "반갑습니다")); // "반갑습니다, 김철수"
2️⃣ 나머지 매개변수 (...rest)
// 여러 개의 인수를 배열로 받기
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
console.log(sum(10, 20)); // 30
// 첫 번째 인수와 나머지 분리
function introduce(name, ...hobbies) {
console.log(`이름: ${name}`);
console.log(`취미: ${hobbies.join(", ")}`);
}
introduce("홍길동", "독서", "영화", "등산");
3️⃣ 전개 연산자 (...spread)
// 배열을 개별 인수로 전개
function add(a, b, c) {
return a + b + c;
}
let numbers = [1, 2, 3];
console.log(add(...numbers)); // 6
// 배열 복사
let arr1 = [1, 2, 3];
let arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
4️⃣ 화살표 함수의 this
let obj = {
name: "객체",
regularFunc: function() {
setTimeout(function() {
console.log(this.name); // undefined (this가 바뀜)
}, 1000);
},
arrowFunc: function() {
setTimeout(() => {
console.log(this.name); // "객체" (this가 유지됨)
}, 1000);
}
};
5️⃣ 구조 분해 할당
// 객체에서 필요한 값만 받기
function createUser({name, age, email = "미입력"}) {
return `${name}(${age}세) - ${email}`;
}
let user = createUser({
name: "홍길동",
age: 25
});
console.log(user); // "홍길동(25세) - 미입력"
// 배열에서 값 받기
function getPosition() {
return [37.5, 127.0]; // 위도, 경도
}
let [lat, lng] = getPosition();
console.log(`위도: ${lat}, 경도: ${lng}`);
6️⃣ 템플릿 리터럴
// 여러 줄 문자열과 변수 삽입
function greet(name, age) {
return `안녕하세요, ${name}님!
올해 ${age}세이시군요.
내년에는 ${age + 1}세가 되시겠네요.`;
}
console.log(greet("홍길동", 25));
7️⃣ async/await (비동기 처리)
// Promise 방식
function getData() {
return new Promise(resolve => {
setTimeout(() => resolve("데이터"), 1000);
});
}
// async/await 방식 (더 읽기 쉬움)
async function processData() {
try {
console.log("데이터 요청 중...");
let data = await getData();
console.log(data);
return "완료";
} catch (error) {
console.log("오류:", error);
}
}
processData(); // "데이터 요청 중..." → (1초 후) "데이터" → "완료"
💡 핵심 정리
- 기본 매개변수: 인수가 없을 때 기본값 설정
- 나머지 매개변수: 여러 인수를 배열로 받기
- 전개 연산자: 배열을 개별 값으로 펼치기
- 화살표 함수: this가 바뀌지 않음
- 구조 분해: 객체/배열에서 필요한 값만 추출
- 템플릿 리터럴: 문자열 안에 변수 삽입
- async/await: 비동기 코드를 동기처럼 작성
📚 마무리 정리
오늘 배운 내용들을 정리하면:
8.1 함수 정의: 선언문, 표현식, 생성자, 화살표 함수 등 다양한 정의 방법
8.2 함수 호출: 일반 호출, 메서드 호출, 생성자 호출, 간접 호출 방법
8.3 함수 인수: 매개변수 처리, 기본값, 가변 인수 등
8.4 재귀 함수: 자기 자신을 호출하는 함수의 활용
8.5 실행 과정: 실행 컨텍스트, 호이스팅, 스코프 체인
8.6 클로저: 함수와 렉시컬 환경의 조합
8.7 이름 공간: 전역 오염 방지와 모듈 패턴
8.8 객체로서의 함수: 일급 객체로서의 함수 특성
8.9 고차 함수: 함수를 다루는 함수
8.10 콜백 함수: 비동기 처리와 이벤트 처리
8.11 ES6+ 기능: 현대적인 함수 기능들
함수는 자바스크립트의 핵심이며, 이러한 개념들을 잘 이해하고 활용하면 더 효율적인 코드를 작성할 수 있습니다.
각 개념들이 서로 연결되어 있으므로, 함수 부분은 좀 더 자세하게 공부를 하는게 좋을 것 같습니다!
💡 오늘 새롭게 알게 된 것
- 함수에 대한 전반적인 내용은 어느 정도 알고 있었는데, 이번에 책을 읽으면서 실제 사용 방법들을 더 깊이 있게 이해하게 되었습니다
🤔 어려웠던 점
- 함수의 전반적인 내용이 알아야 할것도 많고 그래서인지 복잡했어요
- this는 들어봤었음에도 불구하고 볼때마다 새롭게 느껴지는것 같아요
🎯 다음 학습 계획
다음 포스팅에서는 객체에 대해 알아보겠습니다.
'Development > Javascript' 카테고리의 다른 글
모던 자바스크립트 입문 - Chapter 10: 배열의 다양한 기능 💻 (2) | 2025.06.25 |
---|---|
모던 자바스크립트 입문 - Chapter 9: 객체 💻 (3) | 2025.06.24 |
모던 자바스크립트 입문 - Chapter 7: 제어 구문 💻 (1) | 2025.06.22 |
모던 자바스크립트 입문 - Chapter 6: 웹 브라우저에서의 입출력 💻 (3) | 2025.06.21 |
모던 자바스크립트 입문 - Chapter 5: 표현식과 연산자 💻 (0) | 2025.06.20 |