[JavaScript] forEach, map, filter, reduce

codeing999·2022년 7월 17일
0

JavaScript

목록 보기
1/24

공통점

얘네의 공통점은 배열의 각 요소에 대해 반복 실행한다는 점 같다.
즉, for문의 특정 형태들을 매소드화 한거라 볼 수 있을지도.

array.map()

일단 맵이란 단어에서 오는 느낌은 1대1 매핑. 이런거 같다. 즉, 각 원소마다 어떤 처리(인자로 넣은 함수)를 시킨 값들로 이루어진 길이가 같은 배열이 리턴되는 결과물.

array.reduce()

얜 이름에서도 줄어든다는 느낌이 있는데. 설명보니까 최종적으로는 값 하나가 리턴된다고 한다.
그리고 인자로 들어오는 함수의 필수매개변수가 누산기, 현재값 이렇게 두개던데
그 함수가 리턴한게 다음번의 첫인자인 누산기가 되어 또 그 다음번 함수실행의 인자가 되는 느낌.
약간 리커시브함수같은걸 구현해놓은거라 보면 될 듯.

array.forEach()

얘도 설명은 각 요소의 주어진 함수 한번씩 실행이라는데 그럼 map이랑 뭐가 다르지.
map은 어떤 새배열을 리턴하는 거고 얜 리턴을 안하나? 원본 어레이값에도 변화는 안주는 그런건가. map도 안주긴하지만.
단순히 각 요소들마다 출력을 하게 한다든가하는 그런 느낌일 때 쓰는? 어떤 리턴같은게 딱히 필요 없으면 이거 쓰면되는 느낌인가?
어레이 전체에 대해 실행 한단 점에서 그냥 for .. of랑 거의 같아보이는데.

array.filter()

얘는 주어진 조건을 만족한 요소들만을 가지고 새로운 배열을 리턴한다고 한다.
인자로 들어가는 함수의 리턴이 어떤 조건같은건데, 그걸 만족해서 참이되어 true가 리턴되면 그때의 요소는 새 배열에 들어가는 느낌.

간단한 첫인상들은 위와 같고 mdn에서 자세한 설명을 보면

mdn에서 본 함수 설명

arr.map(callback(currentValue[, index[, array]])[, thisArg])

@ callback이라 써있는 거는 map의 인자로 함수가 온다는 말이다.
그리고 그 뒤()안이 것들은 그 함수의 매개변수들인데
currentValue 이 매개변수 하나만 필수란 거고 []로 둘러싸여진 것들은 옵션이다. 거기다가 array의 경우는 []로 두번 둘러싸인거 보면
index 매개변수를 일단 쓸 때에만 추가로 이것도 옵션으로 쓸 수 있단 말 같다.
@ currentValue는 딱히 딴걸 넣는게 아니고 arr의 원소를 뭐라 부를지 아무거나 정해서 써놓으면 된다. 함수선언이기도 하니까 당연한거기도 하지만 헷갈리긴함.
@ index의 경우엔 말그대로 callback함수를 이번 실행할 때의 arr의 index값이다. 이게 원하는 기능을 구현하는데 있어서 인자로 필요하면 그 때만 매개변수에 적어주고 갖다 쓰면 된다.
@ 사용 예시)

answer = arr.filter((v, i) => v != arr[i+1] ) 

각각 v, i라고 부르기로 적어놓고 안에서 사용한 모습.
@ map은 callback 함수를 각각의 요소에 대해 한번씩 순서대로 불러 그 함수의 반환값으로 새로운 배열을 만듭니다.
@ callback 함수는 (undefined도 포함해서) 배열 값이 들어있는 인덱스에 대해서만 호출됩니다. 즉, 값이 삭제되거나 아직 값이 할당/정의되지 않은 인덱스에 대해서는 호출되지 않습니다.
@ map은 호출한 배열의 값을 변형하지 않습니다. 단, callback 함수에 의해서 변형될 수는 있습니다.


arr.reduce(callback[, initialValue])

//mdn꺼가 callback함수 내부를 단순화한거같아서 딴데꺼 참고함.
arr.reduce(callback(accumulator, currentvalue[, currentindex [, array]]){}[, initialValue])

@ 일단 reduce 자체의 필수매개변수는 1개인데 초기값도 써주는게 안전하다고 해서 reduce의 매개변수도 2개라고 보고있어도 될 듯. 그리고 reduce의 매개변수로 오는 함수의 필수 매개변수도 2개이다.
@ initialvValue를 명시 안하면, accumulator가 인덱스0번의 값을 가지면서 reduce는 배열의 인덱스1번에서부터 시작한다.
명시하면 이게 초기의 accumulator 값이되면서 배열의 인덱스0부터 시작한다.

arr.forEach(callback(currentvalue[, index[, array]])[, thisArg])

@ forEach()는 주어진 callback을 배열에 있는 각 요소에 대해 오름차순으로 한 번씩 실행합니다. 삭제했거나 초기화하지 않은 인덱스 속성에 대해서는 실행하지 않습니다.
@ map()과 reduce()와는 달리 undefined를 반환하기 때문에 메서드 체인의 중간에 사용할 수 없습니다. 대표적인 사용처는 메서드 체인 끝에서 부작용(side effect)을 실행하는 겁니다.
@ forEach()는 배열을 변형하지 않습니다. 그러나 callback이 변형할 수는 있습니다.
@ map이나 reduce 안의 callback함수는 리턴값이 필수이지만 얘는 아닌 거 같다.

arr.filter(callback(element[, index[, array]])[, thisArg])

@ filter()는 호출되는 배열을 변화시키지(mutate) 않습니다.

https://velog.io/@nayeon/Array의-map-filter-reduce-forEach-메소드
이 글을 많이 참고함.

느낀점

함수들을 살펴보고나니 대충 어느 상황에서 얘네를 써야할지 감잡을 방법이 생각났다.
원하는 결과가 원본 배열과 크기가 같은 배열이다. -> map
원하는 결과가 원본 배열보다는 크기가 작은 원본의 일부인 배열이다. -> filter
원하는 결과가 값 하나다. 혹은 원본배열과 상관없이 초기화된 배열에서 추가해나갈 배열이다(배열 자체도 하나긴하므로)-> reduce
리턴값을 원하는 건 아니고 그냥 배열 전체에 대해 반복하고 싶다. ->forEach

사용 예시

answers.reduce((ac, v, i) => v == first[i%5]? ac+1: ac, 0);
//reduce 쓸 때 인덱스도 필요해서 i까지 넣어주었고 ac의 초기값 0도 마지막에 , 0으로 들어가있다.
arr.reduce((ac, v, i) => Math.max(...arr) == v? [...ac, i+1] : ac, []);
//reduce가 결과값이 무조건 하나일 필요는 없다. 
//ac를 배열로 초기화 해주고 거기에 원소를 추가해가는 식으로 해서 배열을 리턴하게도 할 수 있다. (객체 자체로 보면 하나이지만 여러 값을 얻을 수 있단거). 
//여기서 중요한건 Math.max 쓸 때도 마찬가지지만 배열을 ...(스프레드) 써서 펼쳐서 인자로 넣어줘야 한단거.
profile
코딩 공부 ing..

0개의 댓글