배열과 메서드 파트의 과제를 풀면서 나의 안 좋은 습관을 발견해버렸다.
바로 모든 문제를 반복문을 써서 풀려고 하는 것이다!

물론 결과는 잘 도출된다. 문제는 코드가 복잡해지고 깔끔하지 않다는 것이다!
그래서 나는 이번 포스팅을 통해
배열에서 쓰이는 반복문(forEach
, for
, for..or
) 대신 쓸 수 있는
map
과 reduce
메서드 활용법을 숙지하려한다.
어떤 경우에 map을 쓸까?
map
은 각 요소를 돌면서 반복 작업을 수행하고, 작업 결과물을 새로운 배열 형태로 얻을 때 사용하면 된다.
내가 풀었던 문제와 내가 쓴 답안은 다음과 같다.
문제: border-left-width를 borderLeftWidth로 변경하기
"my-short-string"같이 여러 단어를 대시(-)로 구분한 문자열을 카멜 표기법을 사용한 문자열 "myShortString"로 변경해주는 함수를 작성해보세요.
대시는 모두 지우고 각 단어의 첫 번째 글자는 대문자로 써주면 됩니다.
예시:
camelize("background-color") == 'backgroundColor';
camelize("list-style-image") == 'listStyleImage';
camelize("-webkit-transition") == 'WebkitTransition';
힌트: split을 사용해 문자열을 배열로 바꾼 다음 join을 사용해 다시 합치면 됩니다.
내가 쓴 답안
const camelize = (str) => {
//str.split(delim)은 delim을 기분으로 문자열을 쪼개준다.
let arr = str.split('-');
for (let i = 1; i< arr.length; i++) {
//i번째 단어부터 알파벳 단위로 나눠서 backWordArr배열에 저장한다.
let backWordArr = arr[i].split('');
// backWordArr배열의 0번째 알파벳을 대문자로 바꿔준 후 capital에 저장해준다.
let capital = backWordArr[0].toUpperCase();
// backWordArr의 0번째 알파벳을 지우고 그 자리에 capital(대문자)를 넣어준다.
backWordArr.splice(0, 1, capital);
// backWordArr의 배열 요소를 모두 합친 후 modifiedWord라는 하나의 문자열로 만들어준다.
let modifiedWord = backWordArr.join('');
//arr배열의 i번째 요소는 modifiedWord로 바뀐다.
arr[i] = modifiedWord;
}
//arr배열의 배열 요소를 모두 합친 후 result라는 하나의 문자열로 만들어준다.
let result = arr.join('');
console.log(result);
return result;
};
camelize("background-color");
camelize("list-style-image");
camelize("-webkit-transition");
나는 문제를 위와 같이 for
문을 사용하여 풀었다. 코드가 상당히 길어져서 한눈에 이해하기 어렵다.
이 for
문을 통해서 하고 싶었던 것은 결국 각 요소를 돌며 반복 작업을 수행하고, 작업 결과물을 새로운 배열 형태로 만든 것이다. 즉 여기서는 for
문 대신 map
을 사용해도 된다는 것이다.
이제 공식 답안을 같이 보자.
공식 답안
function camelize(str) {
return str
.split('-')
.map((word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1))
.join('');
}
같이 분석해보자.
.split('-')
str.split(delim) 메서드는 구분자(delimiter) delim을 기준으로 문자열을 쪼갠다.
즉 여기서 str로 'my-Long-word'가 들어왔다면 split('-')을 통해 [ 'my', 'Long', 'word' ] 배열이 된다.
.map( (word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1) )
arr.map은 배열 요소 전체를 대상으로 함수를 호출하고, 함수 호출 결과를 배열로 반환해준다.
여기서 word는 배열의 요소고, index는 말 그대로 인덱스다.
[ 'my', 'Long', 'word' ]에서 index가 0이라면 배열의 요소를 그대로 둔다.
index가 0이 아니라면 '문자열의 첫번째 글자(word[0])을 대문자로 바꾼 것'과 'word의 1번째 글자부터 끝까지'를 더해준다.
참고로 문자열 내 특정 위치인 pos
에 있는 글자에 접근하려면 [pos]
같이 대괄호를 이용하거나 str.charAt(pos)라는 메서드를 호출하면 된다. 위치는 0부터 시작한다.
let str = `Hello`;
// 첫 번째 글자
alert( str[0] ); // H
alert( str.charAt(0) ); // H
// 마지막 글자
alert( str[str.length - 1] ); // o
참고: https://ko.javascript.info/string#ref-779
문자열
ko.javascript.info
.join('')
map
메소드를 통해서 [ 'my', 'Long', 'word' ]는 [ 'my', 'Long', 'Word' ]라는 배열을 만들었다.
이제 이걸 join 메소드를 통해 [ 'my', 'Long', 'Word' ]의 배열 요소를 모두 합친 후 myLongWord라는 하나의 문자열로 만들어 준다.
어떤 경우에 reduce를 쓸까?
arr.reduce는 배열을 기반으로 값 하나를 도출할 때 사용된다.
문법
let value = arr.reduce(function(accumulator, item, index, array) {
// ...
}, [initial]);
인수로 넘겨주는 함수는 배열의 모든 요소를 대상으로 차례차례 적용되는데, 적용 결과는 다음 함수 호출 시 사용된다.
함수의 인수는 다음과 같다.
accumulator
– 이전 함수 호출의 결과.initial
은 함수 최초 호출 시 사용되는 초깃값을 나타냄(옵션)item
– 현재 배열 요소index
– 요소의 위치array
– 배열
이전 함수 호출 결과는 다음 함수를 호출할 때 첫 번째 인수(previousValue)로 사용된다.
첫 번째 인수는 앞서 호출했던 함수들의 결과가 누적되어 저장되는 '누산기(accumulator)'라고 생각하면 된다.
마지막 함수까지 호출되면 이 값은 reduce의 반환 값이 됩니다.
예제
reduce를 이용해 코드 한 줄로 배열의 모든 요소를 더한 값을 구해보는 코드
let arr = [1, 2, 3, 4, 5];
let result = arr.reduce((sum, current) => sum + current, 0);
alert(result); // 15
reduce에 전달한 함수는 오직 인수를 두 개만 받고 있다. 대개 이렇게 인수를 두 개만 받는다.
이 예제에 관한 자세한 설명은 아래 링크에 들어가서 보자.
https://ko.javascript.info/array-methods#ref-403
배열과 메서드
ko.javascript.info
그럼 이제 reduce를 통해 문제를 풀어보자
문제: 평균 나이 구하기

내가 쓴 답안
let john = { name: "John", age: 25 };
let pete = { name: "Pete", age: 30 };
let mary = { name: "Mary", age: 29 };
let arr = [ john, pete, mary ];
console.log( getAverageAge(arr) ); // (25 + 30 + 29) / 3 = 28
function getAverageAge(users) {
let sum = 0;
for(let i = 0; i < users.length; i++){
sum += users[i].age;
}
return sum / users.length;
}
나는 여기에 for문을 써서 sum에 배열의 요소를 차례차례 더해줬다.
그러나 여기서 reduce를 쓰면 코드가 한 줄로 끝나게 된다.
공식 답안
function getAverageAge(users) {
return users.reduce((prev, user) => prev + user.age, 0) / users.length;
}
let john = { name: "John", age: 25 };
let pete = { name: "Pete", age: 30 };
let mary = { name: "Mary", age: 29 };
let arr = [ john, pete, mary ];
alert( getAverageAge(arr) ); // 28
prev
는 accumulator(이전 함수 호출의 결과)user
는 item(현재 배열 요소)0
은 initial(함수 최초 호출 시 사용되는 초깃값)user.age
: 점 표기법을 이용하여 age라는 키를 가지고 있는 프로퍼티 값을 가져온다.
정리
배열 메서드에는 반복문 대신 쓸 수 있는 map과 reduce 메서드가 있다.
map
은 각 요소를 돌면서 반복 작업을 수행하고, 작업 결과물을 새로운 배열 형태로 얻을 때 사용하면 된다.reduce
는 배열을 기반으로 값 하나를 도출할 때 사용된다.
앞으로 반복문을 쓰기 전에 다른 메서드를 쓸 수 있는지 생각해보자!

'Programming Language > JavaScript' 카테고리의 다른 글
[JavaScript] setTimeout은 현재 실행 중인 스크립트의 처리가 종료된 이후에 실행된다! (0) | 2022.12.23 |
---|---|
[JavaScript] Object.entries(obj)가 반환하는 건 맵이 아닌 '배열'이다! (0) | 2022.11.19 |
[Javascript] 반복문 STOP! split과 join, 그리고 Map 자료구조 (0) | 2022.11.17 |
[Javascript] 대괄호 표기법으로 프로퍼티 값 읽을 때 주의하자! (0) | 2022.11.15 |