프론트엔드 공부를 시작하고, 인강을 구매하여 처음 자바스크립트를 공부할 때, 자바스크립트를 포기했던 파트다...
물론 앞에 내용들도 어렵고 이해가 가지 않았지만, 반복해서 듣고 따라치고해서 겨우 넘겼다,
하지만 이부분은 도저히 이해가 안갔다.
그 후 바로 리액트로 넘어갔다,,,
지금 다시 공부하면서 그때 왜 그랬을까 생각해보면,
개념 위주의 내용이고, 앞에 기본기가 부족해서 그랬던거 같다.
이렇게 사설을 길게 쓴 이유는,
내가 느끼기에 자바스크립트에서 가장 중요한 개념위주의 파트가 2가지 있는 것 같은데, 그 중 하나이기때문이다.
(물론, 모든 파트가 중요하다)
또한, 다시 공부했을 때 내가 여태까지 공부를 잘못된 방향으로 하고있지 않다는걸 간접적으로 느끼게된 파트기도 하다.
이 글에서 알아볼 것
- 순수함수(pure function) & 부수효과(side effect)
- 팩토리함수 (Factory function)
- 클로저 (Closure)
1. 순수함수(pure function) & 부수효과(side effect)
순수함수란 뭘까?
이 고민을 진지하게 처음한건 자바스크립트 인강을 처음 들을때도, 다른 프론트엔드 기술을 공부할때도 아닌,
취미로 공부하는 Unreal 엔진 공부에서였다.
언리얼 엔진 강사가 어떤 함수를 당연하게 순수함수로 설정하고 넘어갔을때
나는 순수함수가 뭐고 왜 순수함수여야하지?? 라는 의문을 가졌다.
그 의문을 이제서야 어느정도 해결할 수 있게되었다.
- 순수함수란?
- 같은 입력(인자)에는 언제나 같은 출력값을 내놓는 함수
- 아무런 부수 효과(side effect)도 트리거 하지 않는 함수
const add = (n1, n2) => {
return n1 + n2;
};
console.log(5, 7); // 12
예를들어 이 간단한 코드를 보면,
add 함수 인자로 어떤 숫자가 결정되면, 어떤 짓을 해도 항상 같은 결과를 내놓을것이다.
그렇다면, 두번째 설명에서 부수 효과(side effect)는 뭘까?
- 부수효과란?
- 함수 외부에서 무언가 바뀌는 효과 = 함수에 의해 외부가 바뀌는 효과
let previousResult = 0;
const addMoreNum = (n1, n2) => {
const sum = n1 + n2;
previousResult = sum;
return sum;
};
console.log(addMoreNum(1, 2));
// previousResult = sum; 이부분이 부수효과를 일으킨다
const brca = ["Messi", "Pedri"];
const printBrca = (b) => {
b.push("Dejong");
console.log(b);
};
printBrca(brca);
// b.push("Dejong"); 이부분이 부수효과를 일으킨다
두 함수 모두 부수효과가 발생하는 함수다.
먼저 첫번째 함수인 addMoreNum 함수를 보면,
함수의 로직에 의해(previousResult = sum;) 외부 변수에(previousResult) 영향을 주는 것을 확인할 수 있다.
두번째 함수인 printBrca 함수 또한,
함수의 로직에 의해(b.push("Dejong");) 외부 배열에(brca) 영향을 주는 것을 확인할 수 있다.
마지막으로 비교를 위해 비순수 함수의 예시를 확인해보자
(위에 부수효과 예제 함수 2개 또한 비순수함수다.)
const addRandom = (n) => {
return n + Math.random();
}
console.log(5); // 결과가 그때그때 다르다
-> 같은 입력값이라 해도 출력값을 예측할 수 없다...즉, 비순수함수
이제 순수함수가 뭔지, 비순수함수가 뭔지 이해가 간다.
그럼 자연스럽게 따라오는 의문점이 있다.
"그래서 뭐가 좋은거고, 뭘 더 지향해야하는지?"
결론부터 말하자면
대부분의 프로그래밍 언어에서, 또는 자바스크립트에서 순수 함수를 지향하는 것은 바람직하다
- 왜??
- 결과를 쉽게 예측 가능하고, 함수에 대한 자세한 로직을 모를다고 가정할때 이상행동을 하지 않을 확률이 높은 함수에 의존하는게 좋기때문
하지만, 모든 함수를 순수함수로 설정할 수는 없다.
로직을 작성하다보면, HTTP 요청이나 서버에 데이터를 보내는등의 어쩔 수 없는 부수효과가 존재할것이고,
이를 좋지 못한 코드로 인식하는 것은 말도 안된다.
- 결론
- 꼭 필요한 경우를 제외하고는 비순수함수, 부수효과를 줄이는 것이 좋다.
2. 팩토리 함수
- 팩토리 함수란?
- 함수안에 함수가 정의되어있는 함수다.
- 왜 사용할까?
- 애플리케이션 여러 부분에서 여러번 호출되는 어떤 함수가 존재한다 했을때, 그 함수가 사전 설정되어있어 쉽게 호출할수있다면, 반복하는 행동을 안해도 될 것이다.
예시를 통해 알아보자
아래 코드처럼 세금을 계산하는 로직이 존재한다고 가정해보자
const calculateTax = (amount, tax) => {
return amount * tax;
}
const someTax1 = calculateTax(100, 0.19);
const someTex2 = calculateTax(100, 0.25);
문제가 전혀 없는 코드다.
굳이 문제점이 존재한다면, 반복이 존재한다는 점과 tax는 세금 종류에 따라 고정되겠지만, amount 값은 사람 또는 상황에 따라 계속 바뀔것이고, 이러면 그때마다 함수를 다르게 호출해야한다.
팩토리 함수는 이런 문제점을 해결해준다.
const createTaxCalculator = (tax) => {
const calculateTax = (amount) => {
return amount * tax;
}
return calculateTax;
}
const someTax3 = createTaxCalculator(0.19);
console.log(someTax3(100));
console.log(someTax3(200));
앞선 코드에서는 세금종류와 사람(또는 상황) 모두 한번에 고려하여 함수를 호출했어야 했지만,
이제는 세금의 종류를 결정하면 사람(또는 상황)이 변하여도 효율적으로 관리할 수 있게되었다.
3. 클로저(Closure) ****중요
가장 중요한 점부터 말하고 하나하나 살펴보겠다.
- 자바스크립트의 모든 함수는 클로저이다
이 파트를 공부하면서 느낀것이 두 가지 존재하는데,
- 1번째 공부 -> ??? 무슨말이지? / 2번째 공부 -> ? 무슨말이지? / 3번째 공부 -> 아...! 무슨말이지? / 4번째 공부 -> 아..
- 자바스크립트는 참 영리? 치밀? 하구나..
솔직히 아직도 100% 이해했다고 자신있게 말하진 못하지만,
어느정도 이해했고, 그것을 정리해볼려한다.
- 자바스크립트에서 함수가 변수를 활용하는 방식
- 각 함수는 자체 렉시컬(Lexical)환경과 전역 환경을 가진다
- 이 렉시컬환경은 함수가 정의될때 새롭게 구성되어, 환경 내부에서 접근할 수 있는 변수를 등록하고 기억한다
- 함수가 접근할 수 있는 변수란 -> 함수 내부에 정의된 변수, 전역 변수
- 그 후 함수는 클로저한다
- 만약 등록되어있는 변수가 바뀌고, 함수가 그 변수를 사용한다면 가장 마지막(최신) 값을 이용한다
- 만약 등록되어있는 변수가 바뀌지 않고, 함수가 그 변수를 사용한다면 저장되어있는 값을 이용한다
- 그래서 클로저란?
- 영어 뜻 그대로이다.. 닫혀있다.
- 그럼 제일 중요하다한 저 문장의 뜻은 '자바스크립트의 모든 함수는 닫혀있다'가 된다
- 뭔 소릴까?
- 클로저를 이해하려면 위에서 설명한 2,3,4번을 살펴보면 된다.
- 영어 뜻 그대로이다.. 닫혀있다.
const dummy = (num) => {
const innerDummy = (innerNum) => {
console.log("내부함수");
return num + innerNum;
};
console.log("외부함수");
return innerDummy;
};
const someDummy = dummy(5);
console.log(someDummy(10));
- 2번 말대로라면, 여기서 내부함수(innerDummy)가 자신의 렉시컬환경에 등록한 변수는 무엇일까?
- num, innerNum 일것이다. (이렇게 변수를 자신의 렉시컬환경에 저장하는 작업은 메우 빠르게 이루어진다.)
위의 코드에서 console.log(someDummy(10))의 결과는 정상적으로 출력된다.
근데, 조금 깊게 생각하면 정상 출력되는 것이 이상하게 느껴질 수 있다.
왜냐하면 다다음글에서 자세히 알아보겠지만, 자바스크립트는 싱글쓰레드이다.
따라서, async 코드가 아닌 이상 하나씩 처리한다.
- 그렇다면 외부함수(dummy)가 종료되면 num 변수는 사라져서 더 이상 사용할수 없을꺼라 생각되겠지만, 이는 사실과 다르다.
- 즉, 변수가 더이상 사용되지 않더라도 자바스크립트는 이를 버리지 않는다,,
- 어떻게?
- 3번을 보자..저장후 함수는 클로저한다 = 저장후 함수는 닫는다 = 저장후 함수는 주변 영향을 받지않는다
- 즉, 외부함수가 종료되어 그 변수가 더 이상 사용되지않아 삭제된다 해도, 내부 함수는 이미 렉시컬에 저장해놨기 때문에 사용할 수 있다.
참...복잡하다
내가 설명을 못하는것도 있겠지만, 그걸 고려해도 복잡하고 말장난 같다
하지만, 클로저 개념은 자바스크립트를 이해하는데 매우 중요한 개념이다.
정리하자면
- 자바스크립트는 사용하지 않는 변수를 버리지 않는다, 어떻게? 함수 렉시컬 환경에 저장되어있고, 각 함수는 주변환경에 클로저되어있기 때문이다
치밀하다
*참고
위에 내용을 들으면 드는 의문..변수를 계속, 모두 저장해놓는다고? 메모리가 낭비되는거 아닌가?
- 최신 자바스크립트 엔진이 판단하기에 변수가 어떤 함수에도 사용되지 않았고, 어떤 곳에서도 사용되지 않았다면 자체적으로 안전하게 삭제해준다
영리하다
정리하면서 다시 느낀거지만, 1회차에 이걸 한번에 이해하는 사람은 천재가 아닐까 싶다.
나도 그런 재능이 있었으면 좋겠지만, 없다는걸 알기에 더욱 노력할수밖에없다
다음 글에는 잠시 부수적인 개념을 살펴볼것이고,
그 다음 글에는 앞서 말했듯이 자바스크립트에서 개념적으로 가장 중요한 두가지중 하나를 알아볼것이다.
'OLD > Javascript' 카테고리의 다른 글
[Javascript] 자바스크립트 비동기(Async)_01 (sync & async 코드, 이벤트 루프, 콜백함수, async / await 키워드) (0) | 2023.02.25 |
---|---|
[Javascript] 자바스크립트 Number & String (부동 소수점, BigInt, 태그된 템플릿) (0) | 2023.02.24 |
[Javascript] 자바스크립트 이벤트(preventDefault(), 버블링(Bubbling) & 캡쳐링(Capturing), 드래그 & 드롭) (2) | 2023.02.22 |
[Javscript] 자바스크립트 this (0) | 2023.02.21 |
[Javascript] 자바스크립트에서의 객체(프로퍼티, 객체 복사, 대괄호를 통한 동적 접근..) (0) | 2023.02.20 |