함수란?
함수다
매개변수를 전달받아 주어진 로직대로 수행한 뒤 반환하는것을 함수라 함
// 함수 정의
function add(x, y) {
return x + y;
}
// 함수 호출
add(2, 5); // 7
함수를 사용하는 이유
- 코드의 재사용: 같은 로직을 필요할 때마다 호출 → 중복 제거
- 유지보수의 편의성: 고칠 데가 한 군데
- 신뢰성: 중복이 줄면 버그 날 구석도 줄어듦
- 가독성: 잘 지은 함수 이름은 그 자체로 코드를 읽기 쉽게 만든다 (코드는 곧 문서)
// 매번 직접 계산하면 중복 + 실수 가능성
var a = (1 + 2) / 2;
var b = (10 + 20) / 2;
// 함수로 추상화하면 이름만 봐도 의도가 보임
function average(x, y) {
return (x + y) / 2;
}
average(1, 2); // 1.5
average(10, 20); // 15
함수 리터럴
함수도 객체다. 다만 일반 객체랑 다른 점은 호출할 수 있다는 것.
함수 리터럴은 function 키워드 + 함수 이름(생략 가능 → 익명 함수) + 매개변수 목록 + 함수 몸체 로 구성된다.
변수에는 함수 리터럴이 평가되어 생성된 "함수 객체"가 할당된다.
// 변수 f 에 들어가는 건 함수 그 자체(객체)
var f = function add(x, y) {
return x + y;
};
console.log(typeof f); // "function"
함수 정의
함수 선언문
함수 이름 생략 불가. 표현식이 아닌 "문(statement)"이라서 변수에 할당 안 되는 것처럼 보이지만,
엔진이 암묵적으로 함수 이름과 같은 이름의 식별자를 만들어서 거기에 함수 객체를 할당해준다. 그래서 함수 이름으로 호출됨.
function add(x, y) {
return x + y;
}
add(2, 5); // 7
함수 표현식
함수는 일급 객체 → 값처럼 변수에 할당 가능. 이게 함수 표현식.
함수 이름은 보통 생략(익명)하고, 호출은 변수 이름으로 한다.
// 익명 함수 표현식 (일반적)
var add = function (x, y) {
return x + y;
};
add(2, 5); // 7
// 기명 함수 표현식 — 함수 이름은 함수 몸체 내부에서만 유효함
var sub = function foo(x, y) {
return x - y;
};
sub(5, 2); // 3
// foo(5, 2); // ReferenceError: foo is not defined
함수 생성 시점과 함수 호이스팅
- 함수 선언문: 런타임 이전(평가 시점)에 함수 객체가 먼저 생성되고 식별자도 거기 바인딩됨 → 선언 전에 호출 가능 (= 함수 호이스팅)
- 함수 표현식: var 변수 호이스팅 규칙을 따름 → 식별자는 undefined로 초기화만 되고, 함수 객체 할당은 런타임에 그 줄을 평가할 때 일어남 → 그 전에 호출하면 TypeError
// 함수 선언문 — OK
console.log(add(2, 5)); // 7
function add(x, y) { return x + y; }
// 함수 표현식 — 이 시점엔 sub === undefined
console.log(sub(2, 5)); // TypeError: sub is not a function
var sub = function (x, y) { return x - y; };
이런 헷갈림 때문에 책에서는 함수 표현식 사용을 권장한다.
Function 생성자 함수
new Function(인수, ..., 함수몸체문자열) 로도 함수를 만들 수 있다. 근데 일반 함수랑 다르게 동작함 — 대표적으로 클로저를 생성하지 않는다. 거의 안 쓴다, 그냥 이런 게 있다 정도.
var add = new Function('x', 'y', 'return x + y');
add(2, 5); // 7
화살표 함수
ES6에서 추가. function 대신 =>, 항상 익명 함수로 정의.
내부 동작이 일반 함수보다 간단함 → this / arguments / super / new.target 바인딩이 없고, prototype 프로퍼티도 없음. (이 차이들은 22장 this에서)
var add = (x, y) => x + y;
add(2, 5); // 7
// 몸체가 여러 줄이면 중괄호 + return
var mul = (x, y) => {
const result = x * y;
return result;
};
함수 호출
매개변수와 인수
여기서 신기한건 매개변수보다 인수가 더 많으면 arguments 객체의 프로퍼티로 보관된다고 함 ㅋㅋ
**kwargs 로 전달되는것도 아니고 이게 뭐임 대체
function add(x, y) {
console.log(arguments) // Arguments(3) [2, 5, 10 ....]
}
add(2, 5, 10)
인수 확인
자바스크립트는 인수 개수/타입 체크 안 한다고 함
그래서 방어 코드를 달아줘야하는데 이 번거로운 짓을 막고자 나온것이 바로 Typescript
매개변수의 최대 개수
없음 근데 유지보수성을 고려하면 0 ~ 3개를 권장한다.
그리고 함수 내부로 전달한 객체를 함수 내부에서 변경하면 함수 외부의 객체가 변경되는 side effect가 발생할 수 있다
반환문
말 그대로 return
만나면 함수 중단에 값을 반환하는 그걸 뜻한다.
함수는 표현식이 때문에 return 키워드가 뱉어준 값을 평가 결과로 작용함
만약 반환문에 아무것도 반환하지 않거나 반환문을 생략하면 암묵적으로 undefined가 반환된다
참조에 의한 전달과 외부 상태의 변경
객체를 전달하면 참조값이 전달된다.
이는 곧 객체에 직접 접근이 가능하다는 뜻임
function changeVal(primitive, obj) {
primitive += 100;
obj.name = 'Kim'
}
var num = 100;
var person = {name: 'jeon'};
changeVal(num, person);
console.log(num); // 100
console.log(person); // {name: 'Kim'}
당연한 결과임
원시값은 불변값이라서 재 할당을 통해 새로운 원시값을 사용함
객체는 아님 근데 ㅋㅋ
이거 코드 추적하기 어려워지니깐 최대한 쓰지 말라고 함
이를 해결하기 위한 방법 중 하나가 바로 객체를 불변객체로 만들어 사용한다고 함
이건 나중에 알아보자
사이드 이펙트가 없는 함수를 순수함수라고 한다
다양한 함수의 형태
즉시 실행 함수 (IIFE)
이전에 봤던 함수 리터럴에서 나온 예시가 이거임
(function () {
var a = 3;
var b = 5;
return a * b;
}());
바로 뒤 생각 안하고 그냥 실행해버리기 ㅋㅋ
즉시 실행 함수도 인수를 전달할 수 있긴 함
var res = (function(a, b) {
return a * b;
}(3, 5))
console.log(res); 15 // 정말 놀랍군
재귀 함수
크아악재귀너무좋아
코테의 신 재귀를 한번 소개해보겠다
자기 자신을 호출하며 탈출 조건을 만날때짜기 반복되는 레전드 문법임
아래 예제 둘은 같은 동작을 함
function countdown(n) {
for (var i = n; i >= 0; i--) console.log(i); // 네이놈간지안나게포문을사용하다니
}
function countdown(n) {
if (n < 0) return;
console.log(n);
countdown(n - 1); // 뭐라는지 한번에 잘 이해가 안되지만 간지는 남 ㅋㅋ
}
자세한 설명은 생략한다.
즉시백준으로달려가1914번하노이탑문제를풀어봐라
사실 백준은 서비스 종료했다
실무에서 사용하면 왜 재귀함수를 사용했어요? 라는 리뷰 500와 무한 붐따가 달릴거니깐 그냥 쓰지말자
중첩 함수
이건 약간 자바의 class와 class 안에 선언된 method를 생각하면 이해가 편함
물론 Java의 private local helper method 비슷하지만, 객체의 멤버 메서드는 아니라는 차이가 있지만
function outer() {
var x = 1;
function inner() {
var y = 2;
console.log(x + y); // 3
}
inner();
}
outer();
암튼 중첩가능
콜백 함수
그냥 함수 인자로 전달해서 안에서 호출하는것
어렵게 생각할 필요 없다
function repeat(n, f) {
for (var i = 0; i < n; i++) {
f(i);
}
}
var logAll = function(i) {
console.log(i);
};
var logOdds = function(i) {
if (i%2) console.log(i);
};
repeat(5, logAll);
repeat(5, logOdds); // 재사용성 GOAT
그냥 함수 안에서 중첩 함수 실행인데 중첩함수가 바깥에서 받아온것일 뿐
이렇게 매개변수를 통해 다른 함수의 내부로 전달되는 함수를 콜백함수 라고 하며,
매개변수를 통해 함수의 외부에서 콜백 함수를 전달받은 함수를 고차함수 라고 한다
근데 익명 함수 리터럴은 repeat 함수를 호출할때마다 다시 평가된다 증발해부리니깐
repeat(5, function(i) {
if(i % 2) console.log(i);
}); // 익명함수, 화살표함수 모두 가능
이러면 한번만 평가되서 효율적임 ㅋㅋ
var logOdds = function(i) {
if (i%2) console.log(i);
};
repeat(5, logOdds); // 재사용성 GOAT
이뿐만 아니라 배열 고차함수에서도 사용된다
var res = [1, 2, 3].map(function (item) {
return item * 2;
})
console.log(res); // [2, 4, 6]
var res = [1, 2, 3].filter(function (item) {
return item * 2;
})
console.log(res); // [1, 3]
var res = [1, 2, 3].reduce(function (acc, cur) {
return acc + cur;
}, 0);
console.log(res); // 6
순수 함수와 비순수 함수
그냥!!! 몇번을 실행해도 동일한 인수가 전달되면 언제나 동일한 값을 반환하는 함수임
딱 테스트 하기 좋은 함수다 이말이죵
만약 내부에 변환하는 값 ex) 지금 시간 이 있다면 그것은 순수함수가 아닌것
비순수함수는 정확히 반대임.
이러면 상태를 추적하기 어려워지니깐 최대한 사용하지 않는것을 권장한다고 한다
참고 자료
- 모던 자바스크립트 Deep Dive 12장
- 원시 값과 객체의 비교 — 함수 인자 전달 방식(값 vs 참조)이 이어짐
- 호이스팅 — 함수 호이스팅 vs 변수 호이스팅
'코딩딩 > Javascript' 카테고리의 다른 글
| 날것 - 전역 변수의 문제점 (0) | 2026.05.19 |
|---|---|
| 날것 - 스코프 (0) | 2026.05.19 |
| 날것 - 원시 값과 객체의 비교 (1) | 2026.04.15 |
| 날것 - 객체 리터럴 (0) | 2026.04.08 |
| 날것 - 타입 변환과 단축 평가 (0) | 2026.04.01 |