명령형 프로그래밍을 기반으로 개발했던 개발자들은 개발하는 소프트웨어의 크기가 커짐에 따라, 복잡하게 엉켜있는 스파게티 코드를 유지보수하는 것이 매우 힘들다는 것을 깨닫게 되었다.
이를 해결하기 위해 함수형 프로그래밍이라는 프로그래밍 패러다임에 관심을 갖게 되었다. 함수형 프로그래밍은 거의 모든 것을 순수 함수로 나누어 문제를 해결하는 기법으로, 작은 문제를 해결하기 위한 함수를 작성하여 가독성을 높이고 유지보수를 용이하게 해준다.
명령형 프로그래밍에서는 메소드를 호출하면 상황에 따라 내부의 값이 바뀔 수 있다. 즉, 우리가 개발한 함수 내에서 선언된 변수의 메모리에 할당된 값이 바뀌는 등의 변화가 발생할 수 있다.
하지만 함수형 프로그래밍에서는 대입문이 없기 때문에 메모리에 한 번 할당된 값은 새로운 값으로 변할 수 없다.
함수형 프로그래밍은 순수함수와 보조 함수의 조합을 통해 로직내에 존재하는 조건문과 반복문을 제거하여 복잡성을 해결하고,변수의 사용을 억제하여 상태변경을 피하려는 프로그래밍이다.
부수 효과가 없는 순수 함수를 1급 객체로 간주하여 파라미터나 반환값으로 사용할 수 있으며, 참조 투명성을 지킬 수 있다.
순수함수는 같은 입력이 주어지면, 같은 출력을 반환해야하고, side effect(부작용)이 없어야한다.
부수 효과(Side Effect)들을 제거한 함수들을 순수 함수(Pure Function)이라고 부르며, 함수형 프로그래밍에서 사용하는 함수는 이러한 순수 함수들이다
let num = 1;
function add(a) {
return a + num;
}
add라는 함수 안에서 전역으로 선언된 변수인 num을 참조하기 때문에 순수함수라고 볼 수 없다.
// 순수함수
function add(a, b) {
return a + b;
}
const result = add(2, 3);
위와 같이 add의 함수가 프로그램 실행에 영향을 미치지 않고 입력 값에 대해서만 값의 변환이 있으므로 순수함수이
let person = { name: "jongmin", age: "26" };
function increaseAge(person) {
person.age = person.age + 1;
return person;
}
increaseAge 함수에서 전역으로 선언된 person의 age 속성을 변경하므로 불변성 유지를 만족하지 못한다.
// 비상태, 불변성 만족
const person = { name: "jongmin", age: "26" };
function increaseAge(person) {
return { ...person, age: person.age + 1 };
}
전역으로 선언된 person 객체를 직접 변경하지 않고, 데이터의 복사본을 만들어, 그 복사본을 사용해 작업을 진행하고 반환한다.
let numbers = [1, 2, 3];
function multiply(numbers, multiplier) {
for (let i = 0; i < numbers.length; i++) {
numbers[i] = numbes[i] * multiplier;
}
}
for문을 사용해서 배열의 각 요소에 multiplier 곱해주는 명령형 프로그래밍이다.
함수형 프로그래밍에서는 마찬가지로 if,switch,for 등 명령문을 사용하지 않고 함수형 코드로 사용해야한다.
// 선언형 프로그래밍
function multiply(number, multiplier) {
return number.map((num) => num * multiplier);
}
위의 예시는 for문을 map으로 대치했고, Javascript 에서는 filter,map,take,reduce 등의 고차함수를 사용한다.
함수형 프로그래밍에서는 함수가 1급 객체가 된다. 1급 객체의 특징은 다음과 같다.
참고: https://velog.io/@fe_jungseok/%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98
단점