Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 리눅스마스터 3과목
- 코딩테스트
- 백준 java
- Kotlin
- 리눅스
- 리눅스마스터 1급 정리
- 연습문제
- 백준 javascript
- 스프링 컨테이너
- java 백준 1차원 배열
- 자바
- 코테
- 자바스크립트 코딩의 기술
- 리눅스마스터1급
- Linux
- toCharArray
- 문자열
- GoingBus
- 반복문
- 카카오
- JavaScript
- 개발자 회고록
- 프로그래머스
- map
- Java
- Memoir
- 고잉버스
- 스프링 빈
- 월간코드챌린지
- 명령어
Archives
- Today
- Total
hoon's bLog
Javascript 자바스크립트 코딩의 기술 7장 유연한 함수를 만들어라 (2) 본문
반응형
7장 유연한 함수를 만들어라
tip34. 부분 적용 함수로 단일 책임 매개변수를 관리하라
- 고차 함수를 이용해 매개변수에 단일 책임을 부여하는 방법을 살펴보자.
- 고차 함수(Higher-Order Function)
- 함수를 파라미터로 전달받거나 연산의 결과로 반환해주는 메서드
- 다른 함수를 반환하므로 최소 2단계의 매개변수가 존재
- 자주 거론되는 함수형 프로그래밍의 핵심이기도 하며, 자바스크립트를 함수형 프로그래밍에 알맞은 언어로 만들어주는 특성
- 함수형 프로그래밍 : 함수형 프로그래밍은 함수를 다른 함수의 파라미터로 넘길 수도 있고 반환(return) 값으로 함수를 받을 수도 있는 프로그래밍 형태
- 웹사이트에 행사 안내 페이지가 있다고 가정하자. 아래 코드를 통해 살펴보자.
- 장소, 건물(building), 관리자(manager) 등은 크게 달라지지 않지만, 행사 내용(program)이 달라질 수 있다.
- 건물, 담당자, 프로그램 또는 전시회라는 세 가지 인수를 받아 하나의 정보 집합으로 결합하는 함수를 만들자.
const building = {
hours: '8 a.m. - 8 p.m.',
address: 'Jayhawk Blvd',
};
const manager = {
name: 'Augusto',
phone: '555-555-5555',
};
const program = {
name: 'Presenting Research',
room: '415',
hours: '3 - 6',
};
const exhibit = {
name: 'Emerging Scholarship',
contact: 'Dyan',
};
function mergeProgramInformation(building, manager, event) {
const { hours, address } = building;
const { name, phone } = manager;
const defaults = {
hours,
address,
contact: name,
phone,
};
return { ...defaults, ...event };
}
- 함수 mergeProgramInformation에서 첫번째, 두번째 매개변수는 (building, manager)로 항상 동일하고, 반복 호출 중이다.
- 함수의 return 값을 받는 변수를 선언하여 함수를 호출하면 아래와 같다.
const programInfo = mergeProgramInformation(building, manager, program);
// {
// hours: "3 - 6",
// address: "Jayhawk Blvd",
// contact: "Augusto",
// phone: "555-555-5555",
// name: "Presenting Research", …}
const exhibitInfo = mergeProgramInformation(building, manager, exhibit);
// {
// address: "Jayhawk Blvd"
// contact: "Dyan"
// hours: "8 a.m. - 8 p.m."
// name: "Emerging Scholarship"
// phone: "555-555-5555"
// }
- 고차함수를 이용해서 단일 책임 매개변수를 만들어 앞에 위치한 2개의 인수를 재사용하면, 아래와 같다.
function mergeProgramInformation(building, manager) {
const { hours, address } = building;
const { name, phone } = manager;
const defaults = {
hours,
address,
contact: name,
phone,
};
return program => {
return { ...defaults, ...program };
};
}
const programInfo = mergeProgramInformation(building, manager)(program);
const exhibitInfo = mergeProgramInformation(building, manager)(exhibit);
- 첫 번째 매개변수 조합은 building, manager 기본 동일한 데이터이며, 두 번째 매개변수는 기초 데이터를 덮어 쓰는 사용자의 지정 정보이다.
- 고차함수 호출법은 괄호에 이어 괄호를 작성하면 된다.
- 반복까지는 제거되지 않았지만 부분 적용을 사용하면 가능하다. 다음 팁에서 배운다. (반환된 함수를 재사용하는 방법)
- 나머지 매개변수는 한번만 사용이 가능하지만, 때로는 반복 사용이 필요한 경우도 있다.
- 배열 데이터가 있거나 원본 데이터에 일대일로 대응되는 추가 데이터가 있는 경우 자주 발생한다.
- 아래는 지역과 새를 결과값 배열로 쌍으로 연결해야 하는 코드이다.
function getBirds(...states) {
return ['meadowlark', 'robin', 'roadrunner'];
}
const birds = getBirds('kansas', 'wisconsin', 'new mexico');
// ['meadowlark', 'robin', 'roadrunner']
const zip = (...left) => (...right) => {
return left.map((item, i) => [item, right[i]]);
};
zip('kansas', 'wisconsin', 'new mexico')(...birds);
// [
// ['kansas', 'meadowlark'],
// ['wisconsin', 'robin'],
// ['new mexico', 'roadrunner']
// ]
- 함수를 함수 zip은 2개의 배열을 쌍으로 결합하는 함수
- 원본 배열을 넘겨 받는 고차함수가 필요(...left)
- 결과값을 배열을 넘겨받아서 결합하는 함수를 반환(...right)
- 변수가 독립적이므로 나머지 매개변수를 두 번 모두 사용 가능하다.
tip35. 커링과 배열 메서드를 조합한 부분 적용 함수를 사용하라
- 다음은 함수의 부분 적용을 통해 변수를 저장해두는 방법을 살펴보자.
- 앞에 팁에서 살펴봤던 예제코드를 이어 간다.
- (building, manager) 를 재사용
- 첫번째 함수 호출의 반환값을 변수에 할당하면 된다.
// 고차함수 이용
const setStrongHallProgram = mergeProgramInformation(building, manager);
const programInfo = setStrongHallProgram(program);
const exhibitInfo = setStrongHallProgram(exhibit);
// 하드 코딩
const setStrongHallProgram = program => {
const defaults = {
hours: '8 a.m. - 8 p.m.',
address: 'Jayhawk Blvd',
name: 'Augusto',
phone: '555-555-5555'
}
return { ...defaults, ...program}
}
const programs = setStrongHallProgram(program);
const exhibit = setStrongHallProgram(exhibit);
- 고차 함수를 이용하면 매개변수를 별도로 분리할 수 있다.
- 하지만, 함수를 완전히 분리하기 전에 함수에 필요한 인수의 수를 줄일 수 있도록, 인수를 분리하는 것이 훨씬 더 중요하다
- 커링(currying) : 한 번에 인수를 하나만 받는 함수
- 커링은 인수 하나를 받는 고차함수가 다른 함수를 반환한다. 이때 반환되는 함수 역시 인수 하나만 받을 수 있다.
- 부분 적용 함수는 원래의 함수보다 항수(인수의 수)가 적은 함수를 반환한다.
(예를 들면, 3개의 인수를 받는 함수인데 2개의 인수를 받는 함수를 반환) - 아래 코드는, 강아지 배열과 필터 조건을 인수로 받은 후 필터링 조건에 맞는 강아지의 이름만 모아서 반환하는 함수.
const dogs = [
{
이름: '맥스',
무게: 10,
견종: '보스턴 테리어',
지역: '위스콘신',
색상: '검정색',
},
{
이름: '도니',
무게: 90,
견종: '래브라도레트리버',
지역: '캔자스',
색상: '검정색',
},
{
이름: '섀도',
무게: 40,
견종: '래브라도레트리버',
지역: '위스콘신',
색상: '갈색',
},
];
function getDogNames(dogs, filter) {
const [key, value] = filter;
return dogs
.filter(dog => dog[key] === value)
.map(dog => dog['이름']);
}
getDogNames(dogs, ['색상', '검정색']);
// ['맥스', '도니']
- 정상적으로 작동하는듯 하나, 2가지 문제 발생한다.
- filter 함수의 제약(=== 를 사용해야 한다. 예를 들면, 무게 20kg 이하인 강아지를 찾기 불가능)
- map은 검사하는 항목만 인수로 받고, 외부 변수는 사용할 수 없다.
- 먼저, 첫번째 문제부터 해결하자. filter와 map 함수를 다른 방식으로 이용하여 기준 체중보다 적게 나가는 강아지를 찾는 함수
function getDogNames(dogs, filterFunc) {
return dogs
.filter(filterFunc)
.map(dog => dog['이름'])
}
getDogNames(dogs, dog => dog['무게'] < 20);
// ['맥스']
- line 3 : filter 함수에함수에 콜백 함수인 filterFunc를 전달한다.
- 하지만 여전히 20과 같은 값을 하드코딩되어 있다. 즉, 20이 아닌 다른 변수를 사용할 때 직접 코딩해서 넣거나, 유효 범위의 충돌이 없는지 확인하는 절차를 거치고 있다.
- 이번엔 아래 코드와 같이, 부분 적용 함수를 이용해보자.
const weightCheck = weight => dog => dog['무게'] < weight;
getDogNames(dogs, weightCheck(20));
// ['맥스']
getDogNames(dogs, weightCheck(50));
// ['맥스', '섀도']
- getDogNames 함수를 다시 작성할 필요 없다.
- 전달하는 값 자체가 필터링하는 기준이 되어, 어떤 무게에서든 재사용이 가능하고, 유효 범위 충돌이 발생할 가능성도 거의 없다.
- 다음은 아래와 같이 커링을 사용해보자.
const identity = field => value => dog => dog[field] === value;
const colorCheck = identity('색상');
const stateCheck = identity('지역');
getDogNames(dogs, colorCheck('갈색'));
// ['섀도']
getDogNames(dogs, stateCheck('캔자스'));
// ['섀도']
- 커링을 사용하면 두 개의 함수와, 두 개의 인수 집합을 제한할 필요 없다.
- 이를 응용하여, 모든 조건을 충족하거나, 최소한 하나의 조건을 충족하는 강아지를 찾는 경우
function allFilters(dogs, ...checks) {
return dogs
.filter(dog => checks.every(check => check(dog)))
.map(dog => dog['이름']);
}
allFilters(dogs, colorCheck('검정색'), stateCheck('캔자스'));
// ['도니']
function anyFilters(dogs, ...checks) {
return dogs
.filter(dog => checks.some(check => check(dog)))
.map(dog => dog['이름']);
}
anyFilters(dogs, weightCheck(20), colorCheck('갈색'));
tip36. 화살표 함수로 문맥 혼동을 피하라
- 화살표 함수를 이용해 문맥 오류를 피하는 방법과 객체에서 this가 메서드에서 어떻게 작동되는지 살펴보자.
const validator = {
message: '는 유효하지 않습니다.',
setInvalidMessage(field) {
return `${field}${this.message}`;
},
};
validator.setInvalidMessage('도시');
// 도시는 유효하지 않습니다.
- this는 객체 validator를 가리킨다.
- setInvalidMessage 메서드가 호출될 때, 함수에서 this 바인딩을 생성하면서 객체를 문맥에 포함시킨다.
- 다음 코드는 객체에 담긴 함수를 다른 함수의 콜백 함수로 사용하는 경우이다.
const validator = {
message: '는 유효하지 않습니다.',
setInvalidMessages(...fields) {
return fields.map(function (field) {
return `${field} : ${this.message}`;
});
},
};
validator.setInvalidMessages('aa','bb')
// ['aa : undefined','bb : undefined']
- 책에서는 에러 난다고 message 속성이 없다고 에러난다고 하지만, 실행시키면 위와 같이 undefined를 반환한다.
- 객체 메서드의 콜백함수의 this는 전역을 바라본다.
- map() 메서드 문맥에서 호출되므로, 바인딩이 validator 객체가 아니고 우리가 원하는 message 값을 가져오지 못한다.
const validator = {
message: '는 유효하지 않습니다.',
setInvalidMessages(...fields) {
return fields.map(field => {
return `${field}${this.message}`;
});
},
};
validator.setInvalidMessages('도시');
// ['도시는 유효하지 않습니다.']
- line 4 : 화살표 함수를 사용하면 문맥을 새로 바인딩하지 않아 validator에 바인딩 된다.
(해당 구간이 화살표 함수 영역인데, 화살표 함수는 this를 만들지 않는다.) - line 5 : this는 validator로 바인딩되어있어서 화살표함수에서 this는 validator로 바인딩된다.
- 아래와 같은 경우도 주의해야 한다.
const validator = {
message: '는 유효하지 않습니다.',
setInvalidMessage: field => `${field} : ${this.message}`,
};
validator.setInvalidMessage('hi');
// "hi : undefined"
- line 3 : 화살표 함수는 새로 문맥을 만들지 않기 때문에 전역을 참고한다!!!!!!
- 때문에 validator 상위에서 this를 가져다 쓰므로 undefined 출력!!!
Reference
자바스크립트 코딩의 기술 요약 / 정리
728x90
반응형
'IT > Javascript' 카테고리의 다른 글
Javascript 자바스크립트 코딩의 기술 8장 클래스로 인터페이스를 간결하게 유지하라 (2) (0) | 2024.02.29 |
---|---|
Javascript 자바스크립트 코딩의 기술 8장 클래스로 인터페이스를 간결하게 유지하라 (1) (2) | 2024.02.28 |
Javascript 자바스크립트 코딩의 기술 7장 유연한 함수를 만들어라 (1) (2) | 2024.02.21 |
Javascript 자바스크립트 코딩의 기술 6장 매개변수와 return 문을 정리하라 (14) | 2024.02.15 |
Javascript 자바스크립트 코딩의 기술 5장 반복문을 단순하게 만들어라 (2) (0) | 2024.02.06 |