JavaScript 고차 함수
고차 함수 내부적으로 for문을 돌며, 인수로 콜백함수를 받을 수 있다.
Array.prototype.sort
배열명.sort()
배열의 요소를 적절하게 정렬. (기본적으로 오름차순)
원본 배열을 직접 변경하며 정렬된 배열을 반환.
문자열 요소들로 이루어진 배열의 정렬은 아무런 문제가 없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 const fruits = ['Banana' , 'Orange' , 'Apple' ];fruits.sort(); console .log(fruits); fruits.reverse(); console .log(fruits);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const points = [40 , 100 , 1 , 5 , 2 , 25 , 10 ];points.sort((a, b ) => { return a - b; }); console .log(points); console .log(points[0 ]); points.sort((a, b ) => { return b - a; }); console .log(points); console .log(points[0 ]);
Array.prototype.forEach
배열명.forEach((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
for문의 대체 메소드. (forEach가 가독성이 더 뛰어나다.)
배열을 순회하며 배열의 각 요소에 대하여 인수로 전달된 콜백 함수를 실행.
2번쨰 인수로 this를 전달 받을 수 있다.
for처럼 중간에 break, continue로 빠져나갈 수 없다.
undefined를 반환함.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const numbers = [1 , 2 , 3 ];let pows = [];for (let i = 0 ; i < numbers.length; i++) { pows.push(numbers[i] ** 2 ); } console .log(pows); pows = []; numbers.forEach(item => pows.push(item ** 2 )); console .log(pows);
콜백을 이용하여 직접 변경도 가능하다.
1 2 3 4 5 6 7 const numbers = [1 , 2 , 3 ];numbers.forEach((item, index, self ) => self[index] = Math .pow(item, 2 )); console .log(numbers);
1 2 3 4 5 6 7 8 9 10 11 12 13 class Numbers { numberArray = []; multiply(arr) { arr.forEach(item => this .numberArray.push(item * item)); } } const numbers = new Numbers();numbers.multiply([1 , 2 , 3 ]); console .log(numbers.numberArray);
화살표 함수는 내부에 this가 없기 떄문에 자신의 상위 스코프의 this를 가져다가 쓴다.
Array.prototype.map
배열명.map((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
배열을 순회하며 배열의 각 요소에 대하여 인자로 주어진 콜백 함수를 실행한다.
map은 요소의 개수만큼 순회하면서 요소를 생성하여 반환한다.
콜백 함수의 반환한 값들이 요소로서 추가된 새로운 배열을 반환한다.
원본 배열은 변경되지 않는다.
희소 배열의 존재하지 않는 요소는 순회 대상에서 제외된다.
this를 전달 받을 수 있다.
1 2 3 4 5 6 7 8 9 10 [1 , 2 , 3 ].map((item, index, self ) => { console .log(`요소값: ${item} , 인덱스: ${index} , this: ${self} ` ); return item; });
1 2 3 4 5 6 7 8 9 10 11 12 13 const numbers = [1 , 4 , 9 ];const roots = numbers.map(item => Math .sqrt(item));console .log(roots); console .log(numbers);
Array.prototype.filter
배열명.filter((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
배열을 순회하며 배열의 각 요소에 대하여 인자로 주어진 콜백 함수를 실행한다.
return 조건식에 부합하는 것을 반환한다.
실행 결과가 true인 배열 요소의 값만을 추출한 새로운 배열을 반환
원본 배열은 변경되지 않는다.
this를 전달 받을 수 있다.
1 2 3 4 5 6 7 8 9 10 [1 , 2 , 3 ].filter((item, index, self ) => { console .log(`요소값: ${item} , 인덱스: ${index} , this: ${self} ` ); return item % 2 ; });
1 2 3 4 5 6 const numbers = [1 , 2 , 3 , 4 , 5 ];const odds = numbers.filter(item => item % 2 );console .log(odds);
Array.prototype.reduce
배열.reduce( (누적값, 현잿값, 인덱스, 요소) => { return 결과 }, 초깃값);
reduce 메소드는 배열을 순회하며 콜백 함수의 이전 반환값과 배열의 각 요소에 대하여 인자로 주어진 콜백 함수를 실행하여 하나의 결과값을 반환한다.
원본 배열은 변경되지 않는다.
첫번째 인수로 콜백 함수 [ 반환값, 요소값, 인덱스, reduce호출한 배열(this)]
두번째 인수는 초기값.
reduce 메소드는 배열을 순회하며 단일값을 구해야 하는 경우에 사용한다.
1 2 3 4 const sum = [1 , 2 , 3 , 4 ].reduce((pre, cur, index, self ) => pre + cur, 0 );console .log(sum);
첫번째 인수로 전달받은 콜백 함수는 4개의 인수를 전달받아 배열의 length만큼 총 4회 호출된다.
이때 콜백 함수로 전달되는 인수와 반환값은 아래와 같다.
구분
콜백 함수에 전달된 인수
콜백 함수의 반환값
pre
cur
index
self
첫번째 순회
0 (초기값)
1
0
[1, 2, 3, 4]
1 (pre + cur)
두번째 순회
1
2
1
[1, 2, 3, 4]
3 (pre + cur)
세번째 순회
3
3
2
[1, 2, 3, 4]
6 (pre + cur)
네번째 순회
6
4
3
[1, 2, 3, 4]
10 (pre + cur
1 2 3 4 5 6 7 8 9 const values = [1 , 2 , 3 , 4 , 5 , 6 ];const average = values.reduce((pre, cur, i, self ) => { return i === self.length - 1 ? (pre + cur) / self.length : pre + cur; }, 0 ); console .log(average);
1 2 3 4 const values = [1 , 2 , 3 , 4 , 5 ];const max = values.reduce((pre, cur ) => (pre > cur ? pre : cur), 0 );console .log(max);
하지만, Math.max 메소드를 사용하는 방법이 보다 직관적이다. min
, max
는 가변인자함수형태로 받는다.
1 2 3 4 const values = [1 , 2 , 3 , 4 , 5 ];const max = Math .max(...values);console .log(max);
1 2 3 4 5 6 7 8 9 10 11 const fruits = ['banana' , 'apple' , 'orange' , 'orange' , 'apple' ];const count = fruits.reduce((pre, cur ) => { pre[cur] = (pre[cur] || 0 ) + 1 ; return pre; }, {}); console .log(count);
1 2 3 4 5 6 const values = [1 , [2 , 3 ], 4 , [5 , 6 ]];const flatten = values.reduce((pre, cur ) => pre.concat(cur), []);console .log(flatten);
중복 요소 제거 ( reduce보다는 filter이용하는게 더 직관적이다. )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const values = [1 , 2 , 1 , 3 , 5 , 4 , 5 , 3 , 4 , 4 ];const result = values.reduce((pre, cur, i, self ) => { if (self.indexOf(cur) === i) pre.push(cur); return pre; }, []); console .log(result); const values2 = [1 , 2 , 1 , 3 , 5 , 4 , 5 , 3 , 4 , 4 ];const result = values2.filter((v, i, self ) => self.indexOf(v) === i);console .log(result);
이처럼 map, filter, some, every, find와 같은 모든 배열 고차 함수는 reduce로 구현할 수 있다.
1 2 const sum = [].reduce((pre, cur ) => pre + cur);
이처럼 빈 배열로 reduce 메소드를 호출하면 에러가 발생한다. reduce 메소드에 초기값을 전달하면 에러가 발생하지 않는다.
1 2 const sum = [].reduce((pre, cur ) => pre + cur, 0 );console .log(sum);
객체의 프로퍼티 값을 합산하는 경우에는 반드시 초기값을 전달해야 한다.
1 2 3 4 5 6 7 8 9 10 11 12 const products = [ { id : 1 , price : 100 }, { id : 2 , price : 200 }, { id : 3 , price : 300 } ]; const priceSum = products.reduce((pre, cur ) => pre + cur.price, 0 );console .log(priceSum);
Array.prototype.some
배열명.some((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
배열을 순회하며 요소 중 하나라도 콜백 함수의 테스트를 통과하면 true, 모든 요소가 콜백 함수의 테스트를 통과하지 못하면 false 를 반환한다.
2번째 인자로 this를 전달 받을 수 있다.
1 2 3 4 5 6 7 8 9 10 11 let result = [5 , 10 , 15 ].some(item => item > 10 );console .log(result); result = [5 , 10 , 15 ].some(item => item < 0 ); console .log(result); result = ['apple' , 'banana' , 'mango' ].some(item => item === 'banana' ); console .log(result);
Array.prototype.every
배열명.every((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
every 메소드는 배열을 순회하며 모든 요소가 콜백 함수의 테스트를 통과하면 true, 요소 중 하나라도 콜백 함수의 테스트를 통과하지 못하면 false 를 반환한다.
2번째 인자로 this를 전달 받을 수 있다.
1 2 3 4 5 6 7 let result = [5 , 10 , 15 ].every(item => item > 3 );console .log(result); result = [5 , 10 , 15 ].every(item => item > 10 ); console .log(result);
Array.prototype.find
배열명.find((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백 함수를 실행하여 그 결과가 참인 첫번째 요소를 반환 한다.
참인 요소가 존재하지 않는다면 undefined를 반환한다.
반드시 첫번쨰 요소만 반환하고 끝난다.
2번째 인자로 this를 전달 받을 수 있다.
아래 예제에서는 프로퍼티 id의 값이 2인 배열 요소가 2개 있다. 그러나 정작 반환하는 것은 name: ‘Kim’ 뿐이다.
1 2 3 4 5 6 7 8 9 10 11 12 const users = [ { id : 1 , name : 'Lee' }, { id : 2 , name : 'Kim' }, { id : 2 , name : 'Choi' }, { id : 3 , name : 'Park' } ]; const result = users.find(item => item.id === 2 );console .log(result);
filter 메소드는 콜백 함수의 실행 결과가 true인 요소만을 추출한 새로운 배열을 반환한다.
따라서 filter의 반환값은 언제나 배열이다.
하지만 find 메소드는 콜백 함수를 실행하여 그 결과가 참인 첫번째 요소를 반환하므로 find의 결과값은 해당 요소값이다.
1 2 3 4 5 [1 , 2 , 2 , 3 ].filter(item => item === 2 ); [1 , 2 , 2 , 3 ].find(item => item === 2 );
Array.prototype.findIndex
배열명.findIndex((item, index, self) => { }); //item: 요소, index: 인덱스, self: this
배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백 함수를 실행하여 그 결과가 참인 첫번째 요소의 인덱스를 반환 한다.
콜백 함수의 실행 결과가 참인 요소가 존재하지 않는다면 -1를 반환한다.
반드시 첫번쨰 요소의 인덱스만 반환하고 끝난다.
2번째 인자로 this를 전달 받을 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const users = [ { id : 1 , name : 'Lee' }, { id : 2 , name : 'Kim' }, { id : 2 , name : 'Choi' }, { id : 3 , name : 'Park' } ]; function predicate (key, value ) { return item => item[key] === value; } let index = users.findIndex(predicate('id' , 2 ));console .log(index); index = users.findIndex(predicate('name' , 'Park' )); console .log(index);