성빈
자바스크립트를 활용한 함수형 프로그래밍 본문
목차
- 함수형 프로그래밍
- 함수 : 1급 객체와 고차 함수
- 함수형 프로그래밍 특징
- 명령형 프로그래밍과 선언적 프로그래밍 비교
- 불변성
- 순수함수
- 데이터 변환
- 고차 함수
함수
함수
연산자를 적용하여 평가할 수 있는 모든 호출 가능한 표현식을 의미
함수의 역할
1. 작업/ 연산 결과의 반환
2. 내/외부 데이터 변경
1급 객체
고차 함수(high order function)
- 매개변수로 전달 가능
- 반환 값으로 전달 가능
→ 함수를 매개변수로 받거나, 함수를 결과로 반환하는 함수
1급 객체 (first class object)
다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체
일반적인 데이터와 마찬가지로 취급한다.
1급 객체(first class citizen)의 요건
- 변수 또는 데이터 구조에 할당 가능
- 매개변수로 전달 가능
- 반환 값으로 전달 가능
1급 객체의 활용 예
1. 함수를 변수에 할당
var log = function(message) {
console.log(message)
}
log("함수를 변수에 할당")
2. 화살표 함수를 상수에 할당
const log = message => console.log(message)
log("화살표 함수를 상수에 할당")
3. 함수를 객체에 포함
const obj = {
message: "함수를 객체에 추가",
log(message) {
console.log(message)
}
}
obj.log(obj.message)
4. 함수를 배열의 원소로 활용
const messages = [
"함수를 배열에 추가",
msg => console.log(msg),
"변수와 동일하게 취급",
msg => console.log(msg)
]
messages[1](messages[0])
messages[3](messages[2])
5. 함수를 매개변수로 활용.. 이해 못함
const insideFn = logger => logger("함수를 다른 함수에 매개변수로 전달")
insideFn(msg => console.log(msg))
(위와 동일한 코드)
const insideFn = (logger) => {
logger("함수를 다른 함수에 매개변수로 전달");
};
const temp = (msg) => {
console.log(msg);
};
insideFn(temp);
6. 함수의 결과로 함수를 반환
var createScream_06 = function(logger) {
return function(message) {
logger(message.toUpperCase() + "!!!")
}
}
const scream_06 = createScream_06(message => console.log(message))
scream_06('createScream은 함수를 반환')
const createScream_07 = logger => message =>
logger(message.toUpperCase() + "!!!")
const scream_07 = createScream_07(message => console.log(message))
scream_07('ES6에서는 더 간편하게 createScream을 만들 수 있음')
scream_06이 scream_07으로 코드가 변하는 과정을, scream01- scream02- scream03- scream04로 나타냄.
(아래 사진 참고)
함수형 프로그래밍
함수형 프로그래밍
함수 사용을 강조하는 소프트웨어 개발 스타일
명령형 프로그래밍과 선언적 프로그래밍 비교
예제 문제를 통해 차이점을 확인해보도록 하겠다.
(예제 1) 문자열을 읽어와 공백은 '-' 문자로, 영문자는 소문자로 변환하는 코드 구현
● 명령형 프로그래밍
- 코드로 원하는 결과를 달성하는 과정에 집중
- 기능을 직접 구현한다.
● 선언적 프로그래밍
- 필요한 결과물에 집중
- 훨씬 더 쉽고 직관적이다.
- 이미 만들어져있는 함수나 라이브러리를 활용한다.
* 정규표현식으로 문자열에서 모든 공백 찾기 : /(우리가 찾고자 하는 문자(공백이면 빈칸으로))/g
한번만 검색하고 그만두는 게 아니라, 문자열 전체를 대상으로 글로벌 탐색을 한다.
(예제 2) DOM 구성
● 명령형 프로그래밍
DOM을 구축하는 과정에 집중
var target = document.getElementById("target");
var wrapper = document.createElement("div");
var headline = document.createElement("h1");
wrapper.id = "welcome";
headline.innerText = "Hello world";
wrapper.appendChild(headline);
wrapper.appendChild(wrapper);
● 선언적 프로그래밍
- 개발자가 고민할 필요 없이, 컴포넌트가 알아서 처리한다.
- 직관적이기 때문에 오류 가능성이 낮다.
const { render } = ReactDOM;
const Welcome = () => (
<div id="welcome">
<h1> Hello world</h1>
</div>
);
render(<Welcome />, document.getElementById('target'));
render함수는 컴포넌트에 있는 지시에 따라 DOM을 만든다.
함수의 특징
1. 불변성 (immutable, 계속)
함수를 수행하더라도 함수에 활용되는 외부의 데이터를 변경하지 않는다.
● 객체에서의 불변성
○ 문제 코드
▶ 문제점
데이터가 함수에 의해 값이 변한다면 함수를 수행했는지 안했는지로 결과가 달라질 수 있기 때문에 코드의 상태를 예측하기 어렵다. 따라서 전달받은 원본을 직접 수정하는 대신에 같은 데이터의 사본을 만들어 사본의 데이터로 연산을 하고, 수정하고 반환한다.
→ 원본은 그대로 유지하면서 함수 활용이 가능하게 된다.
○ 수정된 코드
- 원본 대신 데이터 구조의 복사본을 만들어서 수정 및 활용
- 데이터 원본은 수정되지 않는다.
- Object.assign을 사용하는 방법
var reteColor = function(obj, rating) {
return Object.assign({}, obj, {rating:reating})
}
// 나머지 코드는 동일
- 스프레드 연산자를 활용하는 방법
const rateColor = (obj, rating) =>
({ // 함수의 body가 아닌, 하나의 객체를 선언하기 위해 () 사용
...obj,
rating
})
// 나머지 코드는 동일
● 배열에서의 불변성
○ 문제 코드
Array.prototype.push() 사용
○ 수정된 코드
- 원본을 수정하지 않고, 복사본으로 작업한다.
- array.concat() 을 사용하는 방법
Array.prototype.concat()
- 스프레드 연산자 활용하는 방법
2. 순수 함수
V 순수하지 않은 함수의 요건
1) 매개변수 없음
2) 반환 값 없음
3) 함수 밖 객체의 값(속성)을 변경 → side effect 발생
=> 이 중 하나라도 만족한다면, 순수하지 않은 함수
side effect(부수 효과)
전역 변수를 설정하거나, 함수 내부나 애플리케이션에 있는 다른 상태를 변경하는 것을 말한다.
V 순수 함수와 순수하지 않은 함수 비교
비교1.
(예제 1 : 순수하지 않은 함수)
1) 매개변수 없음, 2) 반환 값 없음, 3) 함수 밖 객체의 값을 변경함
이 세개의 요건을 전부 만족하기 때문에 순수하지 않은 함수이다.
(예제2 : 순수하지 않은 함수)
1) 매개변수와 2) 반환 값은 존재하나, 3) 매개변수로 전달된 함수 밖 객체의 값을 변경하기 때문에
순수하지 않은 함수이다.
(예제3 : 순수 함수)
스프레드 연산자를 사용하여, 원본은 유지하고 복사본으로 작업하여 결과를 반환하므로 side effect가 발생하지 않는다.
따라서 이는 순수함수이다.
비교2.
(예제 1 : 순수하지 않은 함수)
함수나 값을 반환하지 않으며 함수 내부에서 DOM을 직접 수정하기 때문에 side effect가 발생한다.
따라서 순수하지 않은 함수이다.
(예제2 : 순수함수)
객체를 생성하는 부분과 DOM을 직접 수정하는 부분이 분리되어 있어 함수 내부에서 DOM을 직접 수정하지 않는다.
따라서 순수함수이다.
순수함수의 규칙
1) 매개변수 전달
2) 결과 값 반환
3) 함수 밖 객체의 값을 변경하지 않음.
3. 데이터의 변환
순수 함수를 사용해 데이터를 변경하는 함수
원본의 복제본을 생성하여 처리하고 결과를 반환한다.
→ 코드가 덜 명령형이 되고 그에 따라 복잡도도 감소한다.
*** 아래 모든 함수들은 모두 원본 데이터를 수정하지 않는다. ***
1) Array.prototype.join()
배열의 모든 요소를 연결해 하나의 문자열로 만들어 반환
2) Array.prototype.filter(callback)
주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환
Array의 모든 요소를 탐색하고 조건을 충족하면 반환한다.
3) Array.prototype.map(callback) ★★★
배열 내 모든 요소에 대해, 주어진 함수를 호출한 결과를 모아 새로운 배열로 반환
4) Object.keys(object)
주어진 객체의 속성 이름을 열거하는 배열을 반환
5) Array.prototype.reduce(callback, initValue) ★★★
배열 내 모든 요소에 대해 callback을 실행하고 하나의 결과값 반환 (Array 반환 아님)
* initValue (생략 가능)
* callback : (accumulatgor, currentValue, currentIndex, array) => {...}
- accumulator: 콜백의 반환 값 누적 (필수)
- currentValue: 현재 처리할 요소 (필수)
- currentIndex: 현재 처리할 요소의 인덱스 (생략 가능)
- array: reduce()를 호출한 배열 (생략 가능)
(예제 1)
왼쪽 코드를 간결하게 하기 위해, 오른쪽 코드의 삼항연산자를 사용하였다.
(예제 2)
Array.prototype.indexOf()
- 배열 내 지정된 요소를 찾을 수 있는 첫 번째 인덱스 반환
- 존재하지 않으면 -1
4. 고차함수
고차 함수(high order function)
함수를 매개변수로 받거나, 함수를 결과로 반환하는 함수
'React' 카테고리의 다른 글
JSX를 사용하는 리액트 (0) | 2023.11.03 |
---|---|
리액트의 작동 원리 (0) | 2023.11.01 |
React를 위한 자바스크립트2 (0) | 2023.10.30 |
React를 위한 자바스크립트 (0) | 2023.10.28 |
React 시작하기 (0) | 2023.10.27 |