동일한 입력에 대해 항상 동일한 출력을 반환하는 함수
외부상태에 영향을 미치는 side effect가 없는 함수
아래는 순수함수의 예시다.
//순수함수
function add(a, b) {
return a + b;
}
console.log(add(3, 4));//항상 같은 값을 출력함
그리고 아래는 순수함수가 아닌 함수의 예시다.
//순수함수X
let c = 5;
function add2(a, b) {
return a + b + c;
}
console.log(add2(2, 3)); //10
// 함수 밖 변수에 새로운 값을 재할당하면
c = 2;
// 같은 함수임에도 결과가 달라짐
console.log(add2(2, 3)); //7
---------------------------------------
//순수함수X
let D = 10;
function add3(a, b) {
D = b; //함수 내부에서 외부 변수 값을 재할당
return a + b;
}
console.log(add3(2, 5));//함수를 실행하고 나면
console.log(D);//외부 변수 D의 값이 5가 됨.
여기서 잠깐 헷갈릴 수 있는 예시!
아래의 코드에서는 인자로 받은 객체에 아무 변화를 주지 않고 리턴했지만, 순수함수가 아니다.
//순수함수X
let obj = { a : 10 };
function func(obj) {
return obj; // 인자로 받은 객체를 그대로 리턴
}
let obj2 = func(obj); // 새로운 변수에 리턴된 객체를 할당
obj2.a = 50; // 새로운 객체 obj2의 a 값을 변경
console.log(obj2); // { a: 50 }
console.log(obj); // { a: 50 } -- 기존 객체의 값도 변함!!
이렇게 불변성을 지향하는 순수함수와 함수 모듈화를 통해 함수형 프로그래밍을 할 수 있다.
동작과 결과값을 예측하기 쉬워진다.
side effect를 최소화할 수 있다.
함수 단위(모듈)의 코드 재사용이 편해진다.
디버깅이 수월하고 유지보수가 편리해진다.
이때, 불변성(immutability)을 지향한다는 것에 대해 다시 짚어보면,
let obj1 = { val: 10 };
// 순수함수X
function notPureFunc(obj, b) {
obj.val += b;
// 리턴값은 일정하지만,
//함수로 들어온 인자의 상태(= 외부 상태)를 직접 변경함.
}
// 순수함수
function PureFunc(obj, b) {
return { val: obj.val + b };
}
let a = PureFunc(obj1, 5);
console.log(obj1.val); // 기존의 obj1의 val값은 그대로 10
console.log(a.val); // a에 새로 할당한 결과값은 15
위의 예시코드와 같이 순수함수를 사용해 외부에 생성된 객체를 직접 건드리지 않고, 새로운 객체를 리턴하여 외부 객체의 값을 변화시킬 수 있다. 즉, 생성된 객체의 값을 참조만 하는 것이다. 이를 불변성(immutability)을 지킨다고 말한다.
모든 함수를 모듈화하고, 순수함수로 작성할 수는 없겠지만
코드 로직의 흐름을 예측하고,
정확하게 데이터를 다룰 수 있다 !