드림오구
article thumbnail

🌊 배열 고차 함수

 

💡 고차함수란?
함수를 인수로 전달받거나 함수를 반환하는 함수를 말한다.

외부 상태의 변경이나 가변 데이터를 피하고 불변성을 지향하는 함수형 프로그래밍에 기반을 둔다.

함수형 프로그래밍은 순수 함수를 통해 부수 효과를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이려는 노력의 일환이라고 할 수 있다. 

 

Array.prototype.sort (원본 배열 직접 변경)

: 배열의 요소를 정렬한다. (기본적으로 오름차순)

const jobs = ['teacher', 'programmer', 'engineer', 'singer', 'pilot'];
jobs.sort();
console.log(jobs) // ['engineer', 'pilot', 'programmer', 'singer', 'teacher']

const fruits = ['사과', '바나나', '오렌지'];
fruits.sort();
console.log(fruits) // ['바나나', '사과', '오렌지']

const numbers = [1, 3, 5, 7, 9, 11]
numbers.sort();
console.log(numbers) // [1, 11, 3, 5, 7, 9]

numbers.reverse(); // 내림차순으로 변경
console.log(numbers) // [9, 7, 5, 3, 11, 1]

 

  • 내림차순으로 정렬할 땐 sort 메서드를 사용하여 오름차순으로 정렬한 후, reverse 메서드를 사용하여 요소의 순서를 뒤집는다.
  • sort 메서드의 기본 정렬 순서는 유니코드 코드 포인트의 순서를 따른다.
  • 숫자 요소를 정렬할 때는 sort 메서드에 정렬 순서를 정의하는 비교 함수를 인수로 전달해야 한다.
    비교 함수의 반환값이 0보다 작으면 비교 함수의 첫 번째 인수를 우선하여 정렬하고, 0이면 정렬하지 않으며, 0보다 크면 두 번쨰 인 수를 우선하여 정렬한다. → https://dreamogu59.tistory.com/20

 

const numbers = [59, 30, 20, 1, 2, 5, 9, 100]

// 숫자 배열의 오름차순 정렬 
// 비교 함수의 반환값이 0보다 작으면 a를 우선하여 정렬한다.

numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 2, 5, 9, 20, 30, 59, 100]

// 59와 30을 인수로 받는다
// 59 - 30 > 0 이므로 59와 30의 순서가 바껴 [30, 59, ...]으로 정렬이 된다.
// 이것을 반복하여 최종적으로 [1, 2, 5, 9, 20, 30, 59, 100]로 정렬이 된다.


// 숫자 배열의 내림차순 정렬
// 비교 함수의 반환값이 0보다 작으면 b를 우선 정렬한다.
numbers.sort((a, b) => b - a);
console.log(numbers) // [100, 59, 30, 20, 9, 5, 2, 1]

 

객체를 요소로 갖는 배열의 정리 

: 비교함수를 사용하여 비교한다.

const deliveryFood = [
  {
    id: 1,
    food: "pizza",
  },
  {
    id: 2,
    food: "shushi",
  },
  {
    id: 3,
    food: "chicken",
  },
];

//비교 함수
function compare(key) {
  return (a, b) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0);
  // a[key] > b[key]면 1를 반환, a[key] = b[key]면 0을 반환, a[key] < b[key]면 -1을 반환
}

deliveryFood.sort(compare("id"));
console.log(deliveryFood);
// [
//   { id: 1, food: "pizza" },
//   { id: 2, food: "shushi" },
//   { id: 3, food: "chicken" },
// ];
deliveryFood.sort(compare("food"));
console.log(deliveryFood);
// [
//   { id: 3, food: "chicken" },
//   { id: 1, food: "pizza" },
//   { id: 2, food: "shushi" },
// ];

 

Array.prototype.forEach (원본 배열 직접 변경 ❌)

: for문을 대체하는 고차함수다. forEach 메서드는 자신의 호출한 배열을 순회면서 수행해야할 처리를 콜백 함수로 전달받아 반복 실행한다. 원본 배열을 변경하지 않지만 콜백함수를 통해 원본 배열을 변경할 수는 있다. for문의 break, continue가 없기 때문에 시간이 많이 걸리는 복잡한 코드 또는 높은 성능이 필요한 경우가 아니라면 forEach를 권장한다.

 

 

const numbers = [5, 9, 59];
const pows = [];

numbers.forEach(item => pows.push(item ** 2 ));
console.log(pows); // [25, 81, 3481]

// item, index, 메서드를 호출한 배열 자체, 즉 this를 순차적으로 전달
numbers.forEach((item, index, arr) => {
  console.log(`요소값 : ${item}, 인덱스 : ${index}, this : ${JSON.stringify(arr)}`);

})

// 요소값 : 5, 인덱스 : 0, this : [5,9,59]
// 요소값 : 9, 인덱스 : 1, this : [5,9,59]
// 요소값 : 59, 인덱스 : 2, this : [5,9,59]

 

forEach 메서드의 인수 : 콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : undeifned


forEach의 this? 

: forEach 메서드의 콜백함수는 일반 함수로 호출되므로 콜백 함수 내부의 this는 undefined 를 가리킨다.

forEach메서드의 콜백 함수 내부의 this와 메서드 내부의 this를 일치시키려면 forEach 메서드의 두 번째 인수로 forEach 메서드의 콜백 함수 내부에서 this로 사용할 객체를 전달해야한다.

→ 화살표 함수를 사용하면 상위 스코프, 즉 multiplyu 메서드 내부의 this를 그대로 참조할 수 있다.

 

 

 

Array.prototype.map (원본 배열 직접 변경 ❌)

: 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출하고 콜백 함수의 반환값들로 구성된 새로운 배열을 반환한다.

 

forEach와 map 메서드와의 차이점

  forEach map
공통점 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출한다.
차이점 undefined를 반환 콜백 함수의 반환값들로 구성된 새로운 배열 반환

map 메서드의 인수 : 콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : 새로운 배열

 

Array.prototype.filter (원본 배열 직접 변경 ❌)

: 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출하고 콜백 함수의 반환값이 true인 요소로만 구성된 새로운 배열을 반환한다.

 

const numbers = [1, 2, 3, 4, 5];

const odds = numbers.filter(item=> item % 2);
console.log(odds) // [1, 3, 5]

filter 메서드는 nubers 배열의 모든 요소를 순회하면서 콜백 함수를 반복 호출하고 콜백 함수의 반환값이 true인 요소로만 구성된 새로운 배열을 반환한다.

filter 메서드가 생성하여 반환한 새로운 배열의 length는 filter 메서드를 호출한 배열의 length 프로퍼티 값과 같거나 작다.

 

filter 메서드의 인수 : 콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : 콜백함수의 true로 이루어진 새로운 배열

 

* filter 메서드를 사용해 특정 요소를 제거할 경우 특정 요소가 중복되어 있다면 중복된 요소가 모두 제거된다. 특정 요소를 하나만 제거하려면 indexOf 메서드를 통해 특정 요소의 인덱스를 취득한 다음 splice 메서드를 사용한다.

 

Array.prototype.reduce (원본 배열 직접 변경 ❌)

: 자신을 호출한 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 반복 호출한다. 
그리고 콜백함수의 반환값을 다음 순회 시에 콜백 함수의 첫 번째 인수로 전달하면서 콜백 함수를 호출하여 하나의 결과값을 반환한다.

 

const sum = [1, 3, 5, 7].reduce((accumulator, currentValue, index, array) => accumulator + currentValue, 0)
console.log(sum); // 16

reduce 메서드의 인수 : 콜백함수, 초기값

reduce 메서드의 콜백함수의 인수 전달: 초기값 또는 콜백 함수의 이전 반환값, reduce 메서드를 호출한 배열의 요소값, index, array(this)

반환값 : 새로운 배열

 

1 + 3  = 4 → 4 + 5 = 9 → 9 + 7 = 16 

→ 16이라는 결과값을 반환한다.

 

Array.prototype.some (원본 배열 직접 변경 ❌)

: 자신을 호출한 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 호출한다. 반환값이 단 한 번이라도 참이면 true, 모두 거짓이면 false를 반환한다. 또, 호출한 배열이 빈 배열인 경우 언제나 false를 반환한다.

 

const jobs = ['teacher', 'police', 'doctor'].some(item => item === 'police');
console.log(jobs) //true

const empty = [].some(item => item > 59); 
console.log(empty); // false

some 메서드의 인수 : 콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : Boolean값

 

Array.prototype.every (원본 배열 직접 변경 ❌)

: 자신을 호출한 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 호출한다. 반환값이 모두 참이면 true, 단 한 번이라도 거짓이라면 false를 반환한다. 단, 호출한 배열이 빈 배열일 경우 언제나 true를 반환한다.

 

const numbers = [5, 9, 59].every(item => item >  3);
console.log(numbers) // true

const empty = [].every(item => item > 3);
console.log(empty) // true

every 메서드의 인수 :콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : Boolean값

 

Array.prototype.find(ES6) (원본 배열 직접 변경 ❌)

: 자신을 호출한 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 호출한다. 반환값이 true인 첫 번째 요소를 반환한다. true가 존재하지 않는다면 undefined를 반환한다.

요소를 반환하기 때문에 결과값이 배열이 아닌 해당 요소 값이다

 

const numbers = [1, 3, 5, 7, 9];
const newNumber = numbers.find(num => num > 3);
console.log(newNumber) // 5

const users = [
    {id : 1, name : 'Oh'},
    {id : 2, name : 'Gu'},
    {id : 3, name : 'Lee'},
    {id : 2, name : 'Kim'}
]
const newUsers = users.find(users => users.id === 2);
console.log(newUsers) // { id: 2, name : 'Gu'}

 

find 메서드의 인수 :콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : Boolean값 또는 undefined

 

Array.prototype.findIndex (ES6) (원본 배열 직접 변경 ❌)

: 자신을 호출한 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 호출한다. 반환값이 true인 첫 번째 요소의 "인덱스"를 반환한다. true가 존재하지 않는다면 -1를 반환한다.

결과값이 배열이 아닌 해당 요소의 인덱스이다

 

const users = [
    {id : 1, name : 'Oh'},
    {id : 2, name : 'Gu'},
    {id : 3, name : 'Lee'},
    {id : 2, name : 'Kim'}
]
const newUsers1 = users.findIndex(users => users.id === 2);
const newUsers2 = users.findIndex(users => users.id === 4);
console.log(newUsers1) // 1
console.log(newUsers2) // -1

 

findIndex 메서드의 인수 :콜백함수, this

콜백함수의 인수 전달 : item, index, array(this)

반환값 : 인덱스값, true가 없다면 -1

 

Array.prototype.flatMap (ES10) (원본 배열 직접 변경 ❌)

: map을 통해 생성된 새로운 배열을 평탄화한다. 즉 map 메서드와 flat 메서드를 순차적으로 실행하나, 평탄화 깊이를 지정할 수 없고 1단계만 평탄화한다.

 

const arr = ['ogu', 'rabbit'];

//map과 flat을 순차적으로 실행
const newArr = arr.map(x => x.split('')).flat();
console.log(newArr) // [ 'o', 'g', 'u', 'r', 'a', 'b', 'b', 'i', 't' ]

// flatMap은 map을 통해 생성된 새로운 배열을 평탄화
const newArr2 = arr.flatMap(x => x.split(''));
console.log(newArr2) // [ 'o', 'g', 'u', 'r', 'a', 'b', 'b', 'i', 't' ]

 

 

그래서 결론은

이게 가장 궁금했다..

 

원본 배열이 직접 변경되는 고차함수와 아닌 고차함수

 

고차함수의 반환값

 

 

profile

드림오구

@드림오구