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
- Memoir
- GoingBus
- 반복문
- java 백준 1차원 배열
- 프로그래머스
- 백준 java
- 자바
- 연습문제
- JavaScript
- 리눅스
- 리눅스마스터1급
- 스프링 빈
- 스프링 컨테이너
- 개발자 회고록
- 카카오
- map
- Linux
- Kotlin
- 코딩테스트
- Java
- 월간코드챌린지
- 문자열
- 자바스크립트 코딩의 기술
- 고잉버스
- toCharArray
- 리눅스마스터 1급 정리
- 백준 javascript
- 명령어
- 리눅스마스터 3과목
- 코테
Archives
- Today
- Total
hoon's bLog
Javascript 자바스크립트 코딩의 기술 5장 반복문을 단순하게 만들어라 (2) 본문
반응형
5장 배열로 데이터 컬렉션을 관리하라
tip23. filter( )와 find( )로 데이터의 부분집합을 생성하라
다음은 문자열이 담긴 간단한 배열에 필터링을 적용하는 예제 코드이다.
const team = ['Michelle B', 'Dave L', 'Dave C', 'Courtne B', 'Davina M'];
'Dave'.match(/Dav/);
// ["Dav", index: 0, input: "Dave", groups: undefined]
'Michelle'.match(/Dav/);
// null
match()
: 문자열이 정규 표현식과 일치하면 일치한 항목에 대한 정보를 배열로 반환, 일치하지 않으면 null 반환!!filter()
메서드로 수정해보면 다음과 같다.
const daves = team.filter((member) => member.match(/Dav/));
// ['Dave L', 'Dave C', 'Davina M']
- match() 메서드로 team 배열에서 'Dav' 항목이 포함된 항목을 filter() 메서드로 배열로 반환
- 다음은 근무중인 '기념 도서관' 사서를 찾는 예제 코드를 보자
const instructors = [{
name: '짐',
libraries: ['미디어교육정보 도서관']
},{
name: '새라',
libraries: ['기념 도서관', '문헌정보학 도서관']
},{
name: '엘리엇',
libraries: ['중앙 도서관']
}]
let memorialInstructor;
for (let i = 0; i < instructors.length; i++) {
if (instructors[i].libraries.includes('기념 도서관')) {
memorialInstructor = instructors[i];
break;
}
})
- 두번째 사서가 일치하여, 조건에 따라 두번째 루프에서 break
- for문과 if문 대신
find()
메서드로 수정해보자!
const librarian = instructors.find((instructor) => {
return instructor.libraries.includes('기념 도서관');
});
// { name: '새라', libraries: ['기념 도서관', '문헌정보학 도서관']}
find()
: 일치하는 값 return, 없을경우 undefined 반환!- '기념 도서관'을 포함한 instructor 객체의 libraries 프로퍼티 return
- 추후 커링(currying, 다중 인수을 갖는 함수를 단일 인수를 갖는 함수들의 함수열로 바꾸는 것)을 통해 코드를 좀 더 개선해 볼 예정
tip24. forEach( )로 동일한 동작을 적용하라
- map(), filter(), find()와 달리 forEach()는 배열을 전혀 변경하지 않는다.
- 예측 가능하면서도 다른 배열 메서드와 같이 작동하여 함께 연결할 수 있기 때문이다.
forEach()
는 함수의 유효 범위를 벗어나는 작업이 필요한 경우에 가장 좋다.- 반드시 Side Effect가 발생한다는 점을 주의해야 한다.
- 그럼에도 불구하고 사용하는 이유는 체이닝 과정에서 다른 배열 메소드와 결합할 수 있기 때문이다.
- 회원들에게 이메일로 초대장을 보내는 예제 코드로 알아보자!
const sailingClub = ['Lee', 'Andy', 'Kim', 'Mike', 'Song'];
for (let i = 0; i < sailingClub.length; i++) {
sendEmail(salingClub[i]);
}
- sendEmail 함수를 sailingClub의 길이만큼 호출하는 코드
- forEach를 사용하는 예제를 만들어보자
sailingClub.forEach((member) => sendEmail(member));
- 위 코드는 이메일을 보내는 것은 부수 효과(사이드 이펙트)지만, 데이터를 조작하지 않는다.
- 이럴때 forEach()를 사용하면 약간의 예측 가능성을 얻을 수 있다.
tip25. 체이닝으로 메서드를 연결하라
체이닝이란, 값을 다시 할당하지 않고 반환된 객체에 메서드를 즉시 호출하는 것을 의미한다.
앞에 살펴봤던 회원들에게 메일 보내는 예제를 통해 알아보자.
const sailors = [
{
name: 'yi hong',
active: true,
email: 'yh@hproductions.io',
},
{
name: 'alex',
active: true,
email: '',
},
{
name: 'nate',
active: false,
email: '',
},
];
const active = sailors.filter((sailor) => sailor.active);
const emails = active.map(
(member) => member.email || `${member.name}@wiscsail.io`
);
emails.forEach((sailor) => sendEmail(sailor));
- line 19 : active: true 인 사람으로 추리기
- line 21 : email을 가지고 있으면 해당 email 사용, 그렇지 않으면 '이름@wiscsail.io' 형태의 email 사용
- line 25 : line 21의 emails 배열에 있는 sailor를 sendEmail 함수로 메일 발송!
- line 19부터 이를 체이닝을 사용하여 코드를 변경하면,
sailors.filter((sailor) => sailor.active)
.map((sailor) => sailor.email || `${sailor.name}@wiscsail.io`)
.forEach((sailor) => sendEmail(sailor));
- 이렇게 체이닝을 사용하면 변수에 할당하는 과정이 생략된다!
- forEach() 메서드는 배열을 반환하지 않으므로 가장 마지막에 사용해야 한다.
- 언뜻 좋아보이지만 단점은 새로운 메서드를 호출할 때 마다 반환된 배열 전체를 다시 반복한다.
- tip24에서의 for문은 sailors의 길이만큼 3번만 반복하면 될 코드를, 체이닝으로 메서드를 연결하면 filter에서 3번, map에서 2번, forEach에서 2번 총 7번을 반복한다.
- 보기 코드와 같이 데이터가 그리 많지 않은 경우는 for문을 쓰는게 좀 더 이득으로 보인다. 하지만 대용량 데이터를 하면 위와 같이 체이닝으로 리팩토링하는 것도 고려해야 하겠다.
tip26. reduce( )로 배열 데이터를 변환하라
- reduce() : 메서드는 원본 배열과는 크기(길이)와 형태가 다른 새로운 배열을 생성
- 배열을 이용해 다른 새로운 자료구조 데이터를 만들어야 할때 사용한다.
const callback = function(collectedValues, item) {
return [...collectedValues, item]; // 누적된 값을 반환하는 반환값
};
const saying = ['veni', 'vedi', 'veci'];
const initialValue = [];
const copy = saying.reduce(callback, initialValue); // 콜백함수, 기본값을 받는다.
copy; // ['veni', 'vedi', 'veci'];
- 콜백함수의 return [...collectedValues, item] 이 부분을 계속 누적하면서 반환한다.
- 1번째 순회 때는 collectedValues의 값은 initialValue인 []이다. 따라서 첫 순회때 return 값은 [...[], 'veni'] = ['veni']
- 2번째 순회 때는 collectedValues의 값은 [...[], 'veni'] 이므로 return 값은 [...[...[], 'veni'], 'vedi'] = ['veni', 'vedi']
- 3번째 역시 2번째랑 같은 원리로 [...[...[...[], 'veni'], 'vedi'], 'veci'] = ['veni', 'vedi', 'veci']
- 결국 마지막 반환값은 ['veni', 'vedi', 'veci']이다.
- 다음은 고윳값을 분류하는 코드를 보자.
const dogs = [
{
이름: '맥스',
크기: '소형견',
견종: '보스턴테리어',
색상: '검정색',
},
{
이름: '도니',
크기: '대형견',
견종: '래브라도레트리버',
색상: '검정색',
},
{
이름: '섀도',
크기: '중형견',
견종: '래브라도레트리버',
색상: '갈색',
},
];
const colors = dogs.reduce((colors, dog) => {
if (colors.includes(dog['색상'])) {
return colors;
}
return [...colors, dog['색상']];
}, []);
console.log(colors); // ["검정색", "갈색"]
- line 26 : 누적값을 반환하는 코드가 없으면 에러가 발생한다.
- line 27 : [] 정의를 내리지 않았으면 dogs의 첫번째 요소를 사용한다.
- 첫번째 순회 때, colors는 [], dog = {이름: '맥스', 크기: '소형견', 견종: '보스턴테리어', 색상: '검정색'}로 line 26의 return값은 ['검정색']
- 첫번째 return 값은 ['검정색']이 두번째 순회 때, colors의 인수가 되어 colors=['검정색'], dog은 dogs의 두번째 요소인 {이름: '도니', 크기: '대형건', 견종: '래브라도레트리버', 색상: '검정색'} 가 된다.
- 때문에 colors의 색깔중에 dog['색상']인 '검정색'을 포함하고 있기 때문에, 그냥 color('검정색')를 return 하고 세번째 순회의 colors의 인수로 넘긴다.
- reduce()를 이용해 데이터의 일부를 반환해 크기(길이)를 변경했고, 형태도 변경했다.
tip27. for...in 문과 for...of 문으로 반복문을 정리하라
- 필요한 결과와 일치하지 않을 때와 자료구조가 배열이 아닌 경우에는 배열메서드를 사용할 필요 없을 수도 있다.
- 아래 코드는 사용자가 회사를 선택하면 정보를 추가, 삭제하는 작업이므로 맵을 사용하면 쉽게 처리할 수 있다. 이 코드를 통해 for...in, for...of를 살펴보자.
const firms = new Map()
.set(10, 'Zoom')
.set(23, 'Apple')
.set(33, 'Google');
// Map(3) {10 => "Zoom", 23 => "Apple", 33 => "Google"}
- isAvailable() 함수는 이용할 수 있는 회사인지 체크하는 코드인데 그냥 호출용 함수코드
- 이제 선택한 회사들 모두 서비스를 사용할 수 있는지, 없는지 확인해보는 코드를 살펴보자.
function checkConflicts(firms, isAvailable) {
// START:loop
const entries = [...firms];
for (let i = 0; i < entries.length; i++) {
const [id, name] = entries[i];
if (!isAvailable(id)) {
return `${name}는 사용할 수 없습니다`;
}
}
return '모든 회사를 사용할 수 있습니다';
// END:loop
}
function checkConflicts(firms, isAvailable) {
// START:reduce
const message = [...firms].reduce((availability, firm) => {
const [id, name] = firm;
if (!isAvailable(id)) {
return `${name}는 사용할 수 없습니다`;
}
return availability;
}, '모든 회사를 사용할 수 있습니다');
return message;
// END:reduce
}
- 위 코드를
for...in
과for...of
를 사용하면 다음과 같다.
//for...in 사용
function checkConflictsForIn(firms, isAvailable) {
// START:for
for (const id in firms) {
if (!isAvailable(parseInt(id, 10))) {
return `${firms[id]}는 사용할 수 없습니다`;
}
}
return '모든 회사를 사용할 수 있습니다';
// END:for
}
//for...of 사용
function checkConflictsForOf(firms, isAvailable) {
for (const firm of firms) {
const [id, name] = firm;
if (!isAvailable(id)) {
return `${name}는 사용할 수 없습니다`;
}
}
return '모든 회사를 사용할 수 있습니다';
}
결론
배열 메서드이든, forEach든, for iterator 문이든 결국엔 적재적소에 사용하는 것이 중요하다!
메서드의 기능을 까먹지 않도록 계속해서 사용하고 연습해야만, 내 것이 된다!
고로 계속 연습하고 공부하자!
Reference
자바스크립트 코딩의 기술 요약 / 정리
728x90
반응형
'IT > Javascript' 카테고리의 다른 글
Javascript 자바스크립트 코딩의 기술 7장 유연한 함수를 만들어라 (1) (2) | 2024.02.21 |
---|---|
Javascript 자바스크립트 코딩의 기술 6장 매개변수와 return 문을 정리하라 (14) | 2024.02.15 |
Javascript 자바스크립트 코딩의 기술 5장 반복문을 단순하게 만들어라 (1) (0) | 2024.01.24 |
Javascript 자바스크립트 코딩의 기술 4장 조건문을 깔끔하게 작성하라 (0) | 2024.01.18 |
Javascript 자바스크립트 코딩의 기술 3장 특수한 컬렉션을 이용해 코드 명료성을 극대화하라 (3) (0) | 2024.01.17 |