-
전역변수는 프로그램 어디에서든 접근할 수 있어 편리하다.
하지만 이는 반대로 말하면, 전역변수가 사용되는 부분에 오류가 발생하면
프로그램 전체를 뒤져 오류를 찾아야 한다는 뜻이다.
이를 방지하기 위해 데이터와 이를 처리하는 메서드를 하나로 묶고
해당 scope에서만 사용 가능한 전역(클래스) 변수를 둔다.
코드를 연관된 부분끼리 묶어 에러의 범위를 제한하고 외부와는 메시지로 통신하는 것.
이것이 내가 생각하는 객체 지향의 핵심이었다.
그리고 이를 더 극단적으로 발전시켜,
공통으로 사용하는 변수 자체를 없애 에러의 파급 범위를 최소화 하는 것.
이것이 내가 생각한 함수형 프로그래밍에 핵심이다.
순수 함수
- 동일한 인자가 들어갈 경우 항상 같은 값이 나와야 한다.
- 부수적인 효과가 일어나면 안 된다.
- return 값으로만 소통한다.
- 순수함수는 평가 시점이 중요하지 않다.만약 순수함수가 아니라면 동일한 인자를 넣어도 다른 값이 나오는 경우 어떠한 시점에서 함수를 평가할지가 굉장히 중요한데 순수함수는 동일한 인자를 넣으면 항상 같은 값이 나오기 때문에 굳이 평가시점을 따질 필요가 없다.
함수형 프로그래밍의 주된 키워드중 하나는 “순수” 함수이다.
순수 함수엔 여러 조건이 존재하는데,
쉽게 요약하자면 “외부에 영향을 주지도, 받지도 않는 함수”로,
프로그램에서 함수를 호출한 부분을 리턴값으로 바꿔도 프로그램에 변화가 없어야한다.
(참조 투명성)
인자로 받은 배열의 요소 개수를 리턴해주는 함수는 순수 함수이다.
하지만 인자로 받은 배열에 값을 하나 추가하는건 순수 함수가 아니다.
인자로 받았다 해도 배열은 함수 외부의 존재이기 때문이다.
이를 순수 함수로 변경하려면 인자로 받은 배열을 복사해서 값을 추가하고 리턴해주면 된다.
순수 함수는 return 값으로만 소통한다는 것이 이런 의미.
사실상 순수 함수는 무언가를 “계산”해주는 함수 정도로 보면 될듯하다. (이거 복선임)
순수함수는 외부에 아무런 영향을 주지 않는다.
이는 구조적인 에러로 프로그램에 오류가 발생했을때,
순수함수는 디버깅 영역에서 제외할 근거가 된다.
즉 에러의 원인이 될 수 있는, side effect가 존재하는 영역과 아닌 영역을 분리해
에러시 검수해야할 범위를 줄이고 유지 보수성과 확장성을 높이는 것.
이것이 함수형 프로그래밍의 본질이다.
(아마도)객체 지향 vs 함수형 프로그래밍?
체 지향과 함수형 프로그래밍은 서로 배타적인 개념이 아니다.
객체 지향은 서로 관심이 있는 것끼리 모아서 관리를 하자란 느낌이라면
함수형 프로그래밍은 상태를 변화시키는 것과 그렇지 않은 것들을 분리해서 관리하자 라는 느낌.
Javascript는 객체 지향과 함수형이 섞인 언어로,
Javascript를 잘 사용하기 위해선 객체 지향도, 함수형도 잘 알아야 한다.
내가 봤을때 객체 지향은 프로그램을 “설계”하는데 중점을 둔 반면,
함수형 프로그래밍은 코드를 “작성”하는 방법에 중점을 둔 느낌이다.
객체 지향적으로 설계한 코드에 함수형 프로그램의 “불변성”, “참조투명성”을 도입하는 것이
나는 개인적으로 맘에 들었다.
액션, 계산, 데이터
다시 쓰는 함수형 프로그래밍
> 참 좋은데 어떻게 표현할 방법이 없네... 오랜 기간 개발을 공부하게 되면서 여러가지 패러다임의 변화를 겪었는데 그 중에서 인상깊었던 것중에 하나는 객체지향 패러다임에서 함수형 패러다
velog.io
순수 함수와 부가 함수를 처음 분리하는 것은 어렵다.
글쓴이는 이를 쉽게 데이터/계산/액션 3가지로 나눠보라 했다.
<button id="button">0</button> <script> document.getElementById("button").onclick = function() { button.innerText++ } </script>
function App() { // 데이터 const [count, setCount] = useState(0) // 계산 const increase = (value) => value + 1 // 액션 const onClick = () => setCount(increase(count)) // 선언적 패턴 return <button onClick={onClick}>{count}</button> }
전자의 코드는 ‘버튼을 누르면 값이 1 오른다’라는 하나의 기능만을 위해 구현된 코드이다.
이를 순수 함수인 ‘계산’과 부가 함수인 ‘액션’, 그리고 데이터로 나눠보면?
예상외로 생각보다 익숙한 형태일 것이다.
위에서 말했듯 JS는 함수형 프로그래밍을 염두에 둔 언어이고, 우리는 알게 모르게 이를 쓰고 있다.
함수형 프로그래밍을 공부해야하는건 이 때문 😎
불변성
function deepFreeze(object){ Object.freeze(object); object.next=="null" ? (Object.freeze(object.next)) : (deepFreeze(object.next)); }
함수형 프로그래밍의 또다른 특징 ‘불변성’은
데이터의 변경을 최소화해 에러를 최대한 줄이는 것이다.
변수의 값을 변경해야한다면 이를 복사해 새로운 변수에 할당하고
메모리:죽여줘…변수(배열)을 변경하지 않고 값을 리턴하는 map, filter, concat, slice 등 고차함수를 사용한다. (복선)
클래스 변수와 같은 경우엔 Object.freeze 함수로 객체를 readOnly로 바꾼 뒤
필요할떄만 객체를 Object.assign으로 복사해 값을 수정하고
재할당하는 방식으로 불변성을 최대한 지킬 수 이다.
(재할당까지 막으려면 객체를 const로 선언하면 된다)
다차원 객체라면 가장 상위 객체만 freeze/assign 되니 주의.
직접 재귀적으로 들어가서 freeze/assign해줘야한다.
for문 쓰면 외않됀데?
함수형 프로그래밍에선 for문과 if문을 최대한 안쓰는게 좋다고 한다.
배열을 순회하는건 for문이나 map이나 똑같지 않나?
for문도 배열을 복사해서 쓰면 불변성을 지킬 수 있고
map도 return 값을 원본 배열에 재할당하면 불변성이 깨지는데
불변성을 잘 지키는게 중요하지 for 대신 map을 쓰는게 중요한가 생각이 들었다.
const cats = [ { name: 'Mojo', months: 84 }, { name: 'Mao-Mao', months: 34 }, { name: 'Waffles', months: 4 }, { name: 'Pickles', months: 6 } ] var kittens = [] for (var i = 0; i < cats.length; i++) { if (cats[i].months < 7) { kittens.push(cats[i].name) } } console.log(kittens)
const isKitten = cat => cat.months < 7 const getName = cat => cat.name const getKittenNames = cats => cats.filter(isKitten).map(getName) const kittens = getKittenNames(cats) console.log(kittens)
이러한 이유를 찾아 헤매다, 좋은 예제를 찾아서 갖고왔다.
주어진 cats라는 배열에서 나이가 7달 이하인 애옹이만을 찾아야한다 하자.
아래와 같이 코드를 리팩토링하면 2가지 장점이 있다.
- if문을 별도의 함수로 추출하하여 필요시 해당 함수를 재사용도 가능하다.
- cats[i].months < 7이란 코드보다 isKitten이란 함수명이 더 직관적이며,
- for문을 제거함으로서 모든 객체는 const로 선언되었다.for문 내 var i와 push도 제거되었다.
- kittens란 배열은 선언과 즉시에 그 값이 할당되고 (변화가 없고) for문 내 var i와 push도 제거되었다.
const (var와 let보다)를 사용하는 코드는 섹시합니다.
해당 블로그에서 발췌.
요약
1.객체 지향적 구조에 참조투명성과 불변성을 추가하자
2.참조투명성
- 코드를 액션(부가함수)와 계산(순수함수), 데이터로 나눈다
- 모든 입출력을 명시적으로 (parameter와 return값)
3.불변성
- 데이터를 수정할땐 무조건 복사부터
- 가능하면 새로운 변수로, 아니면 원래 변수에 재할당
- let과 var을 사용하지 않기 (가능하다면)
참고한 글
[프론트엔드] 일단 한번 해보세요! 함수형 프로그래밍.
프론트엔드 개발자가 왜 함수형 프로그래밍을 배우고 써야 하는지 이유에 대해서 말해볼까 합니다. 그리고 글 말미에는 더 clean하고 safe한 코드를 작성하기 위해 당장 시작할 수 있는 간단한 팁
velog.io
다시 쓰는 함수형 프로그래밍
> 참 좋은데 어떻게 표현할 방법이 없네... 오랜 기간 개발을 공부하게 되면서 여러가지 패러다임의 변화를 겪었는데 그 중에서 인상깊었던 것중에 하나는 객체지향 패러다임에서 함수형 패러다
velog.io
함수형 프로그래밍을 배워보자!
함수형 프로그래밍에 대해서 이론을 공부해도 감이 잘 오지 않는 분들에게 어떻게 함수형 프로그래밍에 접근을 해나가면 좋을지 도움이 되고자 1부 파트였던 **함수형 사고에 대한 이론과 실습
velog.io
[번역] 자바스크립트에서 for 루프를 다시 생각해보자
이 글은 Joel Thoms의 "자바스크립트에 대한 애정을 언어의 90%를 쓰레기통에 버리면서 다시 발견했던 과정"을 번역한 글을 보고, 번역이 안된 중요 부분을 추가 번역 한 것입니다. [번역] 자바스크
hamait.tistory.com
자바스크립트 3항연산자에 대한 고찰
Introduction 코딩 하는 시간을 100이라고 가정한다면, 요즘 80은 자바스크립트를, 나머지 10씩을 각각 러스트와 파이썬을 하는데 쓰고 있다. 자바스크립트에 삼항연산자가 있고, 물론 러스트와 파이
yceffort.kr
'CS > 기타' 카테고리의 다른 글
HTTP의 특징 5가지 (0) 2023.08.07 GIT - 분산, Merkle tree, 인덱스 (0) 2023.08.07 객체 지향 프로그래밍 (0) 2023.07.31 소스트리 사용법 (0) 2023.07.18 Tokenizer, Lexer, Parser (0) 2023.07.13