순수 함수 는 아래 두 가지 조건을 만족하는 함수다.
각각의 조건을 예시와 함께 살펴보자
입력값이 같다면 언제 호출하든 결과가 같음을 보장한다는 의미이다.
예를 들어, f(2) === 4 였다면, 몇번이고 실행해도 무조건 4가 나와야 한다.
function add(a, b) {
return a + b;
}
외부의 변수를 변경하지 않고 (즉, 부작용이 생길 우려가 없음), 외부 변수나 I/O(파일, 네트워크 등)에 의존하지 않는다는 의미이다.
아래 예시는 외부 변수 counter을 함수 내에서 변경하므로 순수 함수가 아니다.
let counter = 0;
function increase() {
counter++;
return counter;
}
이것을 순수 함수로 변경하면 다음과 같아진다.
function increase(counter) {
return counter + 1;
}
다음처럼, taxRate 라는 외부 상태에 의존하여, 해당 외부 상태가 변경되면 결과도 바뀌는 함수도 순수 함수가 아니다.
function calculatePrice(price) {
return price + price * taxRate;
}
taxRate 도 매개변수로 주어져야 순수 함수라고 할 수 있다.
function calculatePrice(price, taxRate) {
return price + price * taxRate;
}
불변성 이란 값이 한번 정해지면 절대로 바뀌지 않는 성질 을 의미한다.
let user = { name: "도현" };
user.name = "길동";
이 예시는 기존 객체의 속성을 직접적으로 변경했기 때문에, 불변성을 깨는 방식이라고 할 수 있다.
let user = { name: "도현" };
let newUser = { ...user, name: "길동" };
user = newUser;
위 코드에서는 기존 user 객체는 변경되지 않고,
전개 연산자(...user)를 통해 복사된 새로운 객체에 name 값을 변경해 newUser를 생성한다.
즉, 기존 객체는 그대로 유지되며,
새로운 객체를 만들어 값을 바꾸는 방식이기 때문에 불변성을 지키는 예시라고 할 수 있다.
단, user = newUser는 변수 user가 새로운 객체를 가리키도록 참조가 바뀐 것일 뿐,
기존 객체 자체는 변경되지 않았다는 점에서 불변성을 유지한 것이다.
만약, 하나의 객체를 다른 곳에서 공유하고 있다고 해보자.
어느 한 곳에서 객체를 직접 수정했다면, 다른 쪽에도 영향이 갈 것이다.
결국 코드가 점점 스파게티처럼 꼬일 수 있다.
const user = { name: "도현" };
const copied = user; // 다른 파일에서 사용중이라고 가정
copied.name = "길동";
console.log(user.name); // "도현" 을 예상했으나 "길동" 출력
React는 상태 변화가 일어났는지를 판단하고, 만약 그렇다면 리렌더링을 한다.
그런데, 기존 객체를 직접 수정하게 되면, 객체의 참조가 변경되지 않아 변경으로 간주하지 않고, 리렌더링도 발생하지 않는다.
따라서, 상태 기반 UI 프레임워크(예: React)에서는 상태의 불변성을 지켜야
변경 사항을 정확하게 감지하고, 올바르게 리렌더링할 수 있다.
이처럼 불변성과 순수 함수는 예측 가능하고 안정적인 코드를 작성하는 데에 중요한 역할을 한다.
어떤 표현식을 그 결과 값으로 바꿔도 프로그램의 동작이 변하지 않는 특성을 의미한다.
function add(a, b) {
return a + b;
}
const x = add(2, 3); // 항상 5 반환
위 예시에서 add(2, 3)을 언제든지 5로 바꿔도 프로그램 동작에 전혀 영향을 주지 않는다.
이럴 때 우리는 해당 표현식이 참조 투명성(referential transparency)을 만족한다고 말한다.
그리고 함수가 순수 함수라면 자연스럽게 참조 투명성을 갖게 된다.
참조 투명성 덕분에 코드를 읽고 추론하기가 훨씬 쉬워진다.
함수형 표현은 함수를 값처럼 다루는 방식을 말한다.
즉, 함수를 변수에 할당하거나, 다른 함수의 인수로 전달하거나, 함수의 반환값으로 사용할 수 있다는 뜻이다.
함수가 숫자, 문자열 등 다른 데이터 타입과 동등하게 취급된다는 의미다.
즉, 변수에 저장하고, 인자로 전달하며, 반환값으로 사용할 수 있다는 특성이 있다.
이름이 없는 함수를 정의할 수 있다.
주로 즉시 실행되거나 다른 함수의 인수로 전달될 때 유용하다.
자바스크립트의 중요한 특성 중 하나다.
함수가 선언 당시의 스코프(환경)를 기억하여, 함수가 해당 스코프 밖에서 호출되어도 그 내부 변수에 접근할 수 있게 해준다.
고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수를 말한다.
function greet(name) {
return `Hello, ${name}!`;
}
function sayHello(fn, name) {
console.log(fn(name));
}
sayHello(greet, "도현"); // Hello, 도현!
function add(a, b) {
return a + b;
}
함수 이름을 사용해 독립적으로 선언하는 방식이다.
const add = function (a, b) {
return a + b;
};
함수를 변수에 할당하는 방식으로, 익명 함수 또는 이름 있는 함수 모두 가능하다.
const add3 = (a, b) => a + b;
화살표 함수는 function 키워드 대신 =>를 사용하는 간결한 함수 표현 방식이다.
this 바인딩 방식이 일반 함수와 다르며, 콜백 함수나 짧은 로직에서 자주 사용된다.
세 가지 표현 방식의 가장 큰 차이점은 호이스팅(Hoisting)이다.
console.log(foo()); // 3
function foo() {
return 3;
}
const, let으로 선언된 변수는 호이스팅되지만 초기화 전까지 접근할 수 없다.console.log(func1()); // ReferenceError
const func1 = function () {
return 3;
};
const func2 = () => 3;
console.log(func2()); // 3
함수 표현식은 함수를 값으로 만들어 변수에 할당하는 코드이기 때문에
런타임에 이르러서야 함수가 생성된다.
| 표현 방식 | 호이스팅 영향 | 선언 전에 호출 가능 여부 |
|---|---|---|
| 함수 선언문 | 함수 전체가 호이스팅됨 | ✅ 가능 |
함수 표현식 (const) | 변수 선언만 호이스팅, 함수는 런타임에 할당 | ❌ 불가능 (ReferenceError 발생) |
화살표 함수 (const) | 변수 선언만 호이스팅, 함수는 런타임에 할당 | ❌ 불가능 (ReferenceError 발생) |
const greet = function (name) {
return `안녕하세요 ${name} 님!`;
};
console.log(greet("도현"));
greet 변수에 익명 함수가 할당되었고, 이 함수를 greet() 형태로 호출할 수 있다.
function operate(a, b, callback) {
return callback(a, b);
}
const add = function (x, y) {
return x + y;
};
const multiply = function (x, y) {
return x * y;
};
console.log(operate(5, 3, add)); // 8
console.log(operate(5, 3, multiply)); // 15
operate 함수는 세 번째 인자로 함수(callback)를 받는다.
이처럼 다른 함수에 인수로 전달되는 함수를 콜백 함수라고 한다.
function createMultiplier(factor) {
return function (number) {
return number * factor;
};
}
const multiplyByTwo = createMultiplier(2);
const multiplyByTen = createMultiplier(10);
console.log(multiplyByTwo(5)); // 10
console.log(multiplyByTen(5)); // 50
createMultiplier 함수는 다른 함수를 반환한다.
즉, 고차 함수(Higher-order Function)이다.
(function () {
const message = "즉시 실행되는 함수입니다";
console.log(message);
})();
이름 없는 함수를 정의하자마자 즉시 호출하는 패턴이다.
주로 스코프를 격리하거나 초기화 코드를 실행할 때 사용된다.
모듈성과 재사용성 증가
→ 함수를 독립적인 단위로 만들어 다양한 곳에서 재사용할 수 있다.
높은 유연성
→ 함수를 동적으로 생성하고 전달할 수 있어 코드의 유연성이 높다.
코드의 간결성
→ 특히 화살표 함수와 함께 사용될 때 더 간결한 코드 작성이 가능하다.
테스트 용이성
→ 순수 함수와 함께 사용될 경우, 예측 가능한 동작으로 테스트가 쉬워진다.
함수형 프로그래밍은 프로그래밍을 함수의 조합으로 구성하는 선언형(Declarative) 프로그래밍 패러다임이다.
상태(state)와 변경(mutation)을 최소화하고, 순수 함수와 고차 함수를 중심으로 코드를 구성한다.
작은 함수들을 조합해 더 복잡한 기능을 만드는 것.
const add2 = (x) => x + 2;
const mul3 = (x) => x * 3;
const compose = (f, g) => (x) => f(g(x));
const addThenMul = compose(mul3, add2);
console.log(addThenMul(4)); // (4 + 2) * 3 = 18
하나의 인자만 받는 함수를 연속적으로 호출해 최종 결과를 만드는 기법.
function multiply(a) {
return function (b) {
return a * b;
};
}
const double = multiply(2);
console.log(double(5)); // 10
자바스크립트는 함수형 프로그래밍을 지원하는 멀티 패러다임 언어다.
다음과 같은 내장 함수로 함수형 스타일 코드를 쉽게 작성할 수 있다:
map, filter, reduceforEach, find, some, every()=>{} (간결한 표현)Object.freeze() (불변 객체 생성)const numbers = [1, 2, 3, 4];
const doubled = numbers.map((n) => n * 2); // [2, 4, 6, 8]
const evens = numbers.filter((n) => n % 2 === 0); // [2, 4]
const sum = numbers.reduce((acc, cur) => acc + cur, 0); // 10
| 개념 | 설명 |
|---|---|
| 순수 함수 | 동일한 입력 → 동일한 출력, 부작용 없음 |
| 불변성 | 상태 변경 없이 새로운 값 반환 |
| 고차 함수 | 함수를 인자/반환값으로 사용 |
| 함수 합성 | 여러 함수를 연결해 하나의 함수처럼 사용 |
| 커링 | 다중 인자를 나눠서 하나씩 받는 함수 구조화 |
함수형 프로그래밍은 복잡한 상태 관리와 부작용을 줄여 더 안정적이고 유지보수하기 좋은 코드를 만드는 데 매우 유용하다고 할 수 있겠다.