본문 바로가기
JavaScript/모던 자바스크립트 딥다이브

[JS] 배열

by 김춘삼씨의 고양이 2024. 7. 10.

📌 배열

  • 배열(array): 여러 개의 값을 순차적으로 나열한 자료구조
  • 요소(element): 배열이 가지고 있는 값
  • 인덱스(index): 배열의 요소가 갖는 배열에서 자신의 위치를 나타내는 0 이상의 정수값
  • 배열은 요소의 개수, 즉 배열의 길이를 나타내는 length 프로퍼티를 가짐
  • 배열은 배열 리터럴, Array 생성자 함수, Array.of, Array.from 메서드로 생성할 수 있음
  • 배열은 인덱스와 length 프로퍼티를 가져 반복문을 통해 순차적으로 값에 접근하기 적합한 자료구조임
객체와 배열의 차이 객체 배열
구조 프로퍼티 키와 프로퍼티 값 인덱스와 요소
값의 참조 프로퍼티 키 인덱스
값의 순서 X O
length 프로퍼티 X O

 

const arr = ['apple', 'banana', 'orange'];

arr.length; // -> 3

 

📌 자바스크립트의 배열

  • 자바스크립트에서 배열은 객체 타입임 (배열 타입 존재 X)
  • 밀집 배열(dense array): 동일한 크기의 메모리 공간이 빈틈없이 연속적으로 나열된 자료구조
    (배열의 요소는 하나의 데이터 타입으로 통일되어 있으며 서로 연속적으로 인접해있음)
  • 희소 배열(sparse array): 배열의 요소가 연속적으로 이어져 있지 않는 배열
    (배열의 요소를 위한 각각의 메모리 공간은 동일한 크기를 갖지 않아도 되며, 연속적으로 이어져 있지 않을 수도 있음)
  • 자바스크립트의 배열은 일반적인 배열의 동작을 흉내 낸 특수한 객체임 (해시 테이블로 구현된 객체)
  • 자바스크립트 배열은 인덱스를 나타내는 문자열을 프로퍼티 키로 가지며, length 프로퍼티를 갖는 특수한 객체임
일반 배열과 자바스크립트 배열의 차이 일반 배열 자바스크립트 배열
인덱스로 배열 요소에 접근하는 속도 >
요소를 삽입/삭제하는 속도 <

 

 

📌 length 프로퍼티와 희소 배열

  • length 프로퍼티는 요소의 개수, 즉 배열의 길이를 나타내는 0 이상의 정수를 값으로 가짐
  • length 프로퍼티의 값은 배열에 요소를 추가하거나 삭제하면 자동 갱신됨
  • length 프로퍼티 값에 임의의 숫자 값을 명시적으로 할당할 수 있음
  • 현재 length 프로퍼티 값보다 작은 숫자 값을 할당하면 배열의 길이가 줄어들음
  • 현재 length 프로퍼티 값보다 큰 숫자 값을 할당하는 경우 length 프로퍼티 값은 변경되지만 실제 배열은 변경되지 않음
    (희소 배열이 생성될 수 있음)
  • 자바스크립트는 희소 배열을 문법적으로 허용함
  • 희소 배열은 length와 배열 요소의 개수가 일치하지 않으며, length는 희소 배열의 실제 요소 개수보다 언제나 큼
  • 배열을 생성할 경우 성능 최적화를 위해 희소 배열을 생성하지 않도록 같은 타입의 요소를 연속적으로 위치시키는 것이 좋음

 

📌 배열 생성

배열 리터럴

  • 가장 일반적이고 간편한 배열 생성 방식
  • 배열 리터럴에 요소를 생략하면 희소 배열이 생성됨
const arr1 = [1, 2, 3];

const arr2 = [1, , 3]; // 희소 배열
console.log(arr2); // [1, empty, 3]

 

Array 생성자 함수

  • 전달된 인수가 1개이고 숫자인 경우 length 프로퍼티 값이 인수인 배열을 생성함
    (이때 생성되는 배열은 희소 배열)
const arr = new Array(10);

console.log(arr); // [empty * 10]

 

  • 전달된 인수가 없는 경우 빈 배열을 생성함
const arr = new Array();

console.log(arr); // []

 

  • 전달된 인수가 2개 이상이거나 숫자가 아닌 경우 인수를 요소로 갖는 배열을 생성함
const arr = new Array('apple', 'banana');

console.log(arr); // ['apple', 'banana']

 

  • Array 생성자 함수는 new 연산자와 함께 호출하지 않더라도 배열을 생성하는 생성자 함수로 동작함 

 

Array.of

  • Array.of 메서드는 전달된 인수를 요소로 갖는 배열을 생성함
  • 전다로딘 인수가 1개이고 숫자이더라도 인수를 요소로 갖는 배열을 생성함
Array.of(1); // -> [1]

Array.of(1, 2, 3); // -> [1, 2, 3]

Array.of('string'); // -> ['string']

 

Array.from

  • Array.from 메서드는 유사 배열 객체 또는 이터러블 객체를 인수로 전달받아 배열로 변환하여 반환함
Array.from({ length: 2, 0: 'a', 1: 'b' }); // -> ['a', 'b']

Array.from('Hello'); // -> ['H', 'e', 'l', 'l', 'o']

 

  • Array.from을 사용하면 두 번째 인수로 전달한 콜백 함수를 통해 값을 만들면서 요소를 채울 수 있음
  • 두 번째 인수로 전달한 콜백 함수에 첫 번째 인수에 의해 생성된 배열의 요소값과 인덱스를 순차적으로 전달하면서 호출하고, 콜백 함수의 반환값으로 구성된 배열을 반환함 
Array.from({ length: 3 }); // -> [undefined, undefined, undefined]

Array.from({ length: 3 }, (_, i) -> i); // -> [0, 1, 2]

 

📌 배열 요소의 참조

  • 배열 요소를 참조할 때는 대괄호([]) 표기법을 사용하며, 대괄호 안에는 인덱스가 와야 함
  • 인덱스는 값을 참조할 수 있다는 의미에서 객체의 프로퍼티 키와 같은 역할을 함
  • 배열에서 존재하지 않는 요소를 참조하면 undefined를 반환함 (희소 배열도 undefined 반환)
const arr = [1, 2];

console.log(arr[0]); // 1

console.log(arr[3]); // undefined

 

📌 배열 요소의 추가와 갱신

  • 존재하지 않는 인덱스를 사용해 값을 할당하면 새로운 요소가 추가됨
  • 현재 배열의 length 값보다 큰 인덱스로 새로운 요소를 추가하면 희소 배열이 됨
  • 이미 요소가 존재하는 요소에 값을 재할당하면 요소값이 갱신됨
  • 정수 이외의 값을 인덱스처럼 사용하면 요소가 생성되는 것이 아니라 프로퍼티가 생성됨
    추가된 프로퍼티는 length 프로퍼티 값에 영향을 주지 않음
const arr = [0];

// 배열 요소의 추가
arr[1] = 1;
console.log(arr[1]); // 1

// 희소 배열
arr[100] = 100;
console.log(arr); // [0, 1, empty * 98, 100]

// 요소값의 갱신
arr[1] = 10;
console.log(arr); // [0, 10, empty * 98, 100]

 

📌 배열 요소의 삭제

  • 배열은 사실 객체이기 때문에 배열의 특정 요소를 삭제하기 위해 delete 연산자를 사용할 수 있음
  • delete 연산자는 객체의 프로퍼티를 삭제하기 때문에 요소를 완전히 삭제하지 못해 희소 배열을 만들게 됨
  • delete 연산자 대신 Array.prototype.splice 메서드를 사용하는 것이 좋음
const arr = [1, 2, 3];

arr.splice(1, 1);

console.log(arr); // [1, 3]

 

📌 배열 메서드

  • 배열에는 원본 배열을 직접 변경하는 메서드와 원본 배열을 직접 변경하지 않고 새로운 배열을 생성하여 반환하는 메서드가 있음
  • 원본 배열을 직접 변경하는 메서드는 외부 상태를 직접 변경하는 부수 효과가 있기 때문에 가급적 원본 배열을 직접 변경하지 않는 메서드를 사용하는 것이 좋음

 

Array.isArray

  • Array 생성자 함수의 정적 메서드
  • 전달된 인수가 배열이면 true, 배열이 아니면 false를 반환함
// true
Array.isArray([]);
Array.isArray([1, 2]);
Array.isArray(new Array());

// false
Array.isArray();
Array.isArray({});
Array.isArray(1);
Array.isArray(null);
Array.isArray(undefined);

 

Array.prototype.indexOf

  • 원본 배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환함
  • 원본 배열에 인수로 전달한 요소와 중복되는 요소가 여러 개 있다면 첫 번째로 검색된 요소와 인덱스를 반환함
  • 원본 배열에 인수로 전달한 요소가 존재하지 않으면 -1을 반환함
  • indexOf 메서드는 배열에 특정 요소가 존재하는지 확인할 때 유용함
  • ES7에서 도입된 Array.prototype.includes 메서드를 사용하면 가독성이 더 좋음
const arr = ['apple', 'banana', 'orange', 'grape'];

arr.indexOf('orange'); // -> 2

 

Array.prototype.push

  • 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하고 변경된 length 프로퍼티 값을 반환함
  • push 메서드는 원본 배열을 직접 변경함
  • push 메서드는 성능 면에서 좋지 않고 원본 배열을 직접 변경하기 때문에 ES6의 스프레드 문법을 사용하는 것이 좋음
const arr = [1, 2];

// push 메서드 사용
arr.push(3, 4);

console.log(arr); // [1, 2, 3, 4]

// ES6 스프레드 문법 사용
const newArr = [...arr, 5, 6];

console.log(newArr); // [1, 2, 3, 4, 5, 6]
console.log(arr); // [1, 2, 3, 4]

 

Array.prototype.pop

  • 원본 배열에서 마지막 요소를 제거하고 제거한 요소를 반환함
  • 원본 배열이 빈 배열이면 undefined를 반환함
  • pop 메서드는 원본 배열을 직접 변경함
  • push와 pop 메서드를 사용하면 스택을 쉽게 구현할 수 있음
const arr = [1, 2, 3];

let res = arr.pop();
console.log(res); // 3

console.log(arr); // [1, 2]

 

Array.prototype.unshift

  • 인수로 전달받은 모든 값을 원본 배열의 선두에 요소로 추가하고 변경된 length 프로퍼티 값을 반환함
  • unshift 메서드는 원본 배열을 직접 변경함
  • unshift 메서드는 원본 배열을 직접 변경하기 때문에 ES6의 스프레드 문법을 사용하는 것이 좋음
const arr = [1, 2];

// unshift 메서드 사용
arr.unshift(3, 4);

console.log(arr); // [3, 4, 1, 2]

// ES6 스프레드 문법 사용
const newArr = [5, 6, ...arr];

console.log(newArr); // [5, 6, 3, 4, 1, 2]
console.log(arr); // [3, 4, 1, 2]

 

Array.prototype.shift

  • 원본 배열에서 첫 번째 요소를 제거하고 제거한 요소를 반환함
  • 원본 배열이 빈 배열이면 undefined를 반환함
  • shift 메서드는 원본 배열을 직접 변경함
  • shift와 push 메서드를 사용하면 큐를 쉽게 구현할 수 있음
const arr = [1, 2, 3];

let res = arr.shift();
console.log(res); // 1

console.log(arr); // [2, 3]

 

Array.prototype.concat

  • 인수로 전달된 값들(배열 또는 원시값)을 원본 배열의 마지막 요소로 추가한 새로운 배열을 반환함
  • 인수로 전달한 값이 배열인 경우 배열을 해체하여 새로운 배열의 요소로 추가함
  • concat 메서드는 원본 배열을 직접 변경하지 않음
  • push와 unshift 메서드는 concat 메서드로 대체할 수 있음
    • push와 unshift 메서드를 사용할 경우 원본 배열을 반드시 변수에 저장해 두어야 하고, concat 메서드를 사용할 경우 반환값을 반드시 변수에 할당받아야 함
    • 인수로 전달받은 값이 배열인 경우 push와 unshift 메서드는 배열을 그대로 원본 배열의 마지막/ 첫 번째 요소로 추가하지만, concat 메서드는 인수로 전달받은 배열을 해체하여 새로운 배열의 마지막 요소로 추가함
  • concat 메서드는 ES6의 스프레드 문법으로 대체할 수 있음
const arr1 = [1, 2];
const arr2 = [3, 4];

// concat 메서드 사용
const res1 = arr1.concat(arr2);
console.log(res1); // [1, 2, 3, 4];

const res2 = arr1.concat([30, 40]);
console.log(res2); // [1, 2, 30, 40]

// 원본 배열은 변경되지 않음
console.log(arr1); // [1, 2]

// ES6 스프레드 문법 사용
const res3 = [...arr1, ...arr2];
console.log(res3); // [1, 2, 3, 4]

 

Array.prototype.splice

  • 원본 배열의 중간에 요소를 추가하거나 중간에 있는 요소를 제거하는 경우 사용
  • splice 메서드는 원본 배열을 직접 변경함
  • splice 메서드는 3개의 매개변수가 있음
    • start: 원본 배열의 요소를 제거하기 시작할 인덱스
      start만 지정하면 원본 배열의 start부터 모든 요소를 제거함
      start가 음수인 경우 배열의 끝에서의 인덱스를 나타냄 (-n이면 마지막에서 n번째 요소를 가리킴)
    • deleteCount: start부터 제거할 요소의 개수
      deleteCount가 0인 경우 아무런 요소도 제거되지 않음
    • items: 제거한 위치에 삽입할 요소들의 목록 (생략 가능)
  • indexOf 메서드를 통해 특정 요소의 인덱스를 취득한 후 splice 메서드를 사용해 배열의 특정 요소를 제거할 수 있음
  • filter 메서드를 사용해 특정 요소를 제거할 수 있지만 특정 요소가 중복된 경우 모두 제거됨
const arr = [1, 2, 3, 4, 5];

// splice 메서드 사용
// (원본 배열의 인덱스 1부터 2개의 요소를 제거하고 그 자리에 새로운 요소 20, 30을 삽입)
const res = arr.splice(1, 2, 20, 30);

// 제거한 요소가 배열로 반환됨
console.log(res); // [2, 3]

// 원본 배열이 변경됨
console.log(arr); // [1, 20, 30, 40, 50]

 

Array.prototype.slice

  • 인수로 전달된 범위의 요소들을 복사하여 배열로 반환함
  • slice 메서드는 원본 배열을 직접 변경하지 않음
  • slice 메서드는 2개의 매개변수를 가짐
    • start: 복사를 시작할 인덱스
      start가 음수일 경우 배열의 끝에서의 인덱스를 나타냄 (-n이면 배열의 마지막 n개의 요소를 복사)
    • end: 복사를 종료할 인덱스 (이 인덱스에 해당하는 요소는 복사되지 않음)
      end는 생략 가능하며 생략 시 기본값은 length 프로퍼티 값임
  • slice 메서드의 인수를 모두 생략하면 원본 배열의 복사본을 생성하여 반환하며, 이때 복사본은 얕은 복사를 통해 생성됨
  • slice 메서드가 복사본을 생성하는 것을 이용해 arguments, HTMLCollection, NodeList 같은 유사 배열 객체를 배열로 변환할 수 있음
const arr = [1, 2, 3, 4];

// slice 메서드 사용
arr.slice(0, 1); // -> [1]

arr.slice(1, 3); // -> [2, 3]

// 원본 배열은 변경되지 않음
console.log(arr); // [1, 2, 3, 4]

// 얕은 복사
const copy = arr.slice():
console.log(copy); // [1, 2, 3, 4]
console.log(copy === arr); // false

 

Array.prototype.join

  • 원본 배열의 모든 요소를 문자열로 반환한 후, 인수로 전달 받은 문자열, 즉 구분자로 연결한 문자열을 반환함
  • 구분자는 생략 가능하며 기본 구분자는 콤마(,)임
const arr = [1, 2, 3];

arr.join(); // -> '1,2,3,4'

arr.join(''); // -> '1234'

arr.join('@'); // -> '1@2@3'

 

Array.prototype.reverse

  • 원본 배열의 순서를 반대로 뒤집으며 변경된 배열을 반환함
  • reverse 메서드는 원본 배열을 직접 변경함
const arr = [1, 2 ,3];

const res = arr.reverse();

console.log(res); // [3, 2, 1]
console.log(arr); // [3, 2, 1]

 

Array.prototype.fill

  • 인수로 전달받은 값을 배열의 처음부터 끝까지 요소로 채움
  • fill 메서드의 두 번째 인수로 요소 채우기를 시작할 인덱스를 전달할 수 있고,
    세 번째 인수로 요소 채우기를 멈출 인덱스를 전달할 수 있음
  • fill 메서드를 사용하면 배열을 생성하면서 특정 값으로 요소를 채울 수 있음
  • Array.from 메서드를 사용하면 두 번째 인수로 전달한 콜백 함수를 통해 요소값을 만들면서 배열을 채울 수 있음
    Array.from 메서드는 두 번째 인수로 전달한 콜백 함수에 첫 번째 인수에 의해 생성된 배열의 요소값과 인덱스를 순차적으로 전달하면서 호출하고, 콜백 함수의 반환값으로 구성된 배열을 반환함
  • fill 메서드는 원본 배열을 직접 변경함
const arr1 = [1, 2, 3];

// fill 메서드 사용
arr1.fill(0);
console.log(arr1); // [0, 0, 0]

const arr2 = new Array(5);
console.log(arr2); // [empty * 5]

arr2.fill(1);
// const arr2 = new Array(5).fill(1);
console.log(arr2); // [1, 1, 1, 1, 1]

// Array.from 메서드 사용
const makeArray = (length = 0) => Array.from({ length }, (_, i) => i);
// const makeArray = (length = 0) => Array.from(new Array(length), (_, i) => i);

console.log(makeArray(4)); [0, 1, 2, 3]

 

Array.prototype.includes

  • 배열 내에 특정 요소가 포함되어 있는지 확인하여 true 또는 false를 반환함
  • includes 메서드의 첫 번째 인수로 검색할 대상을 지정하고,
    두 번째 인수로 검색을 시작할 인덱스를 전달할 수 있음
    두 번째 인수를 생략할 경우 기본값 0이 설정되고
    두 번째 인수에 음수를 전달하면 length 프로퍼티 값과 음수 인덱스를 합산하여 (length + index) 검색 시작 인덱스를 설정함
  • indexOf 메서드를 사용해도 배열 내 특정 요소가 포함되어 있는지 확인할 수 있지만 반환값이 -1인지 확인해야 하고 배열에 NaN이 포함되어 있는지 확인할 수 없는 문제가 있기 때문에 includes 메서드를 사용하는 것이 좋음
const arr = [1, 2, 3];

arr.includes(2); // -> true

arr.includes(100); // -> false

arr.includes(1, 1); // -> false

// 배열에 요소 3이 포함되어 있는지 인덱스 2(arr.length - 1)부터 확인함
arr.includes(3, -1); // -> true

 

Array.prototype.flat

  • 인수로 전달한 깊이만큼 재귀적으로 배열을 평탄화함
  • 중첩 배열을 평탄화할 깊이를 인수로 전달할 수 있으며, 인수를 생략할 경우 기본값은 1임
  • 인수로 Infinity를 전달하면 중첩 배열 모두를 평탄화함
[1, [2, [3, [4]]]].flat(); // -> [1, 2, [3, [4]]]

[1, [2, [3, [4]]]].flat(1); // -> [1, 2, [3, [4]]]

[1, [2, [3, [4]]]].flat(2); // -> [1, 2, 3, [4]]

[1, [2, [3, [4]]]].flat(Infinity); // -> [1, 2, 3, 4]

 

📌 배열 고차 함수

  • 고차 함수: 함수를 인자로 전달받거나 함수를 반환하는 함수
  • 고차 함수는 외부 상태의 변경이나 가변 데이터를 피하고 불변성을 지향하는 함수형 프로그래밍에 기반을 두고 있음
  • 함수형 프로그래밍: 순수 함수와 보조 함수의 조합을 통해 로직 내에 존재하는 조건문과 반복문을 제거하여 복잡성을 해결하고 변수의 사용을 억제하여 상태 변경을 피하려는 프로그래밍 패러다임
  • 함수형 프로그래밍은 순수 함수를 통해 부수 효과를 최대한 억제하여 오류를 피하고 프로그램의 안정성을 높이려는 노력의 일환

 

Array.prototype.sort

  • 배열의 요소를 정렬하고 정렬된 배열을 반환함
  • sort 메서드는 원본 배열을 직접 변경함
  • sort 메서드의 기본 정렬 순서는 유니코드 코드 포인트의 순서를 따름
    배열의 요소가 숫자 타입이라 할지라도 배열의 요소를 일시적으로 문자열로 변환한 후 유니코드 코드 포인트의 순서를 기준으로 정렬
  • 숫자 요소를 정렬할 때에는 sort 메서드에 정렬 순서를 정의하는 비교 함수를 인수로 전달해야 함
    • 비교 함수의 반환값 < 0: 비교 함수의 첫 번째 인수를 우선하여 정렬
    • 비교 함수의 반환값 = 0: 정렬하지 않음
    • 비교 함수의 반환값 > 0: 두 번재 인수를 우선하여 정렬
  • sort 메서드는 timsort 알고리즘을 사용하여 정렬함
// 문자열 배열
const fruits = ['Banana', 'Oragne', 'Apple'];

// 오름차순 정렬
fruits.sort();
console.log(fruits); // ['Apple', 'Banana', 'Orange']

// 숫자 배열
const points = [40, 100, 1, 5, 2, 25, 10];

// 숫자 배열의 오름차순 정렬
points.sort((a, b) => a - b);
console.log(points); // [1, 2, 5, 10, 25, 40, 100]

// 숫자 배열의 내리차순 정렬
points.sort((a, b) => b - a);
console.log(points); // [100, 40, 25, 10, 5, 2, 1]

 

Array.prototype.forEach

  • 반복문을 추상화한 고차 함수. 내부에서 반복문을 통해 자신을 호출한 배열을 순회하면서 수행해야 할 처리를 콜백 함수로 전달받아 반복 호출함
  • for문을 대체할 수 있는 고차 함수
  • forEach 메서드의 콜백 함수는 forEach 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), forEach 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
  • forEach 메서드는 원본 배열을 변경하지 않지만 콜백 함수를 통해 원본 배열을 변경할 수는 있음
  • forEach 메서드는 for문과 달리 break, continue문을 사용할 수 없어 배열의 모든 요소를 빠짐없이 모두 순회하며 중간에 순회를 중단할 수 없음 (희소 배열의 경우 존재하지 않는 요소는 순회 대상에서 제외됨)
  • forEach 메서드는 for문에 비해 성능이 좋지는 않지만 가독성은 더 좋음
const numbers = [1, 2, 3];
const pows = [];

numbers.forEach(item => pows.push(item ** 2));
console.log(pows); // [1, 4, 9]

// forEach 메서드는 콜백 함수를 호출하면서 3개(요소값, 인덱스, this)의 인수를 전달함
['a', 'b', 'c'].forEach((item, index, arr) => {
  console.log(`요소값: ${item}, 인덱스: ${index}, this: ${JSON.stringify(arr)}`);
});
/*
  요소값: a, 인덱스: 0, this: ['a','b','c']
  요소값: b, 인덱스: 1, this: ['a','b','c']
  요소값: c, 인덱스: 2, this: ['a','b','c']
*/

 

Array.prototype.map

  • 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출하며, 콜백 함수의 반환값로 구성된 새로운 배열을 반환함
  • map 메서드는 원본 배열을 직접 변경하지 않음
  • map 메서드는 요소값을 다른 값으로 매핑한 새로운 배열을 생성하기 위한 고차 함수
  • map 메서드가 생성하여 반환하는 새로운 배열의 length 프로퍼티 값은 map 메서드를 호출한 배열의 length 프로퍼티 값과 반드시 일치함
    map 메서드를 호출한 배열과 map 메서드가 생성하여 반환한 배열은 1:1 매핑함
  • map 메서드의 콜백 함수는 map 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), map 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
const numbers = [1, 4, 9];

const roots = numbers.map(item => Math.sqrt(item));

// map 메서드는 새로운 배열 반환함
console.log(roots); // [1, 2, 3]

// 원본 배열은 변경되지 않음
console.log(arr); // [1, 4, 9]

 

Array.prototype.filter

  • 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출하며, 콜백 함수의 반환값이 true인 요소로만 구성된 새로운 배열을 반환함
  • filter 메서드는 원본 배열을 직접 변경하지 않음
  • filter 메서드는 자신을 호출한 배열에서 필터링 조건을 만족하는 특정 요소만 추출하여 새로운 배열을 만들고 싶을 때 사용함
  • filter 메서드가 생성하여 반환하는 새로운 배열의 length 프로퍼티 값은 map 메서드를 호출한 배열의 length 프로퍼티 값과 같거나 작음
  • filter 메서드의 콜백 함수는 filter 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), filter 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
  • filter 메서드는 자신을 호출한 배열에서 특정 요소를 제거하기 위해 사용할 수 있음
    이 때 특정 요소가 중복되어 있다면 중복된 요소가 모두 제거됨
const numbers = [1, 2, 3, 4, 5];

// filter 메서드를 이용해 numbers 배열에서 홀수인 요소만 필터링함
const odds = numbers.filter(item => item % 2);
console.log(odds); // [1, 3, 5]

const users = ['Kim', 'Lee', 'Park'];

// filter 메서드를 이용해 users 배열에서 조건과 일치하지 않는 요소를 제거함
const newUsers = users.filter(item => item !== 'Park');
console.log(newUsers);

 

Array.prototype.reduce

  • 자신을 호출한 배열을 모든 요소를 순회하며 인수로 전달받은 콜백 함수를 반복 호출하며, 콜백 함수의 반환값을 다음 순회 시에 콜백 함수의 첫 번째 인수로 전달하면서 콜백 함수를 호출하여 하나의 결과값을 만들어 반환함
  • reduce 메서드는 원본 배열을 직접 변경하지 않음
  • reduce 메서드는 첫 번째 인수로 콜백 함수, 두 번째 인수로 초기값을 전달받음
  • reduce 메서드의 콜백 함수에는 4개의 인수, 초기값 또는 콜백 함수의 이전 반환값, reduce 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), reduce 메서드를 호출한 배열 자체(arr), 즉 this가 전달됨
  • reduce 메서드는 초기값과 배열의 첫 번째 요소값을 콜백 함수에게 인수로 전달하면서 호출하고 다음 순회에는 콜백 함수의 반환값과 두 번째 요소값을 콜백 함수의 인수로 전달하면서 호출하고 이러한 과정을 반복하여 하나의 결과값을 반환함
  • reduce 메서드를 호출할 때는 초기값을 생략하지 않고 전달하는 것이 안전함
  • reduce 메서드는 자신을 호출한 배열의 모든 요소를 순회하며 하나의 결과값을 구해야 하는 경우에 사용함 
const sum = [1, 2, 3, 4].reduce((accumulator, currentValue, index, array) => {
  accumulator + currentValue
}, 0);

console.log(sum); // 10
/* reduce 메서드의 활용 */
// 평균 구하기
const vals1 = [1, 2, 3, 4, 5, 6];

const avg = vals1.reduce((acc, cur, i, { length }) => {
  return i === length - 1 ? (acc ++ cur) / length : acc + cur;
}, 0);

console.log(avg); // 3.5

// 최대값 구하기
const vals2 = [1, 2, 3, 4, 5];

const max = vals2.reduce((ac,, cur) => (acc > curr ? acc : cur), 0;

console.log(max); // 5

// 요소의 중복 횟수 구하기
const fruits = ['banana', 'apple', 'orange', 'orange', 'apple'];

const count = fruits.reduce((acc, cur) => {
  acc[cur] = (acc[cur] || 0) + 1;
  return acc;
}, {});

console.log(count); // {banana: 1, apple: 2, orange: 2}

// 중첩 배열 평탑화
const vals3 = [1, [2, 3], 4, [5, 6]];

const flatten = vals3.reduce((acc, cur) => acc.concat(cur), []);

console.log(flatten); // [1, 2, 3, 4, 5, 6]

// 중복 요소 제거
const vals4 = [1, 2, 1, 3, 5, 4, 5, 3, 4, 4];

const res = vals4.reduce(
  (unique, val, i, _values) =>
    _values.indexOf(val) === i ? [...unique, val] : unique,
  []
);

console.log(res); // [1, 2, 3, 5, 4]

 

Array.prototype.some

  • 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출하며, 콜백 함수의 반환값이 단 한번이라도 참이면 true, 모두 거짓이면 false를 반환함
  • 배열의 요소 중에 콜백 함수를 통해 정의한 조건을 만족하는 요소가 1개 이상 존재하는지 확인하여 그 결과를 불리언 타입으로 반환함
  • some 메서드를 호출한 배열이 빈 배열인 경우 언제나 false를 반환함
  • some 메서드의 콜백 함수는 some 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), some 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
[5, 10, 15].some(item => item > 10); // -> true

[5, 10, 15].some(item => item < 0); // -> false

['apple', 'banana', 'mango'].some(item => item === 'mango'); // -> true

[].some(item => item > 3); // -> false

 

Array.prototype.every

  • 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출하며, 콜백 함수의 반환값이 모두 참이면 true, 단 한 번이라도 거짓이면 false를 반환함
  • 배열의 모든 요소가 콜백 함수를 통해 정의한 조건을 모두 만족하는지 확인하여 그 결과를 불리언 타입으로 반환함
  • every 메서드를 호출한 배열이 빈 배열인 경우 언제나 true를 반환함
  • every 메서드의 콜백 함수는 every 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), every 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
[5, 10, 15].every(item => item > 3); // -> true

[5, 10, 15].every(item => item > 10); // -> false

[].every(item => item > 3); // -> true

 

Array.prototype.find

  • 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출하여 반환값이 true인 첫 번째 요소를 반환함
    콜백 함수의 반환값이 true인 요소가 없으면 undefined를 반환함
  • find 메서드의 콜백 함수는 find 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), find 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
  • find 메서드는 콜백 함수의 반환값이 true인 첫 번째 요소를 반환하므로 find의 결과값은 배열이 아닌 해당 요소값임
const users = [
  { id: 1, name: 'Lee' },
  { id: 2, name: 'Kim' },
  { id: 2, name: 'Choi' },
  { id: 3, name: 'Park' }
];

// id가 2인 첫 번째 요소를 반환함
users.find(user => user.id === 2); // -> {id: 2, name: 'Kim'}

 

Array.prototype.findIndex

  • 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출하여 반환값이 true인 첫 번째 요소의 인덱스를 반환함
    콜백 함수의 반환값이 true인 요소가 없으면 -1을 반환함
  • findIndex 메서드의 콜백 함수는 findIndex 메서드를 호출한 배열의 요소값(arr[i])과 인덱스(i), findIndex 메서드를 호출한 배열 자체(arr), 즉 this를 순차적으로 전달받을 수 있음
const users = [
  { id: 1, name: 'Lee' },
  { id: 2, name: 'Kim' },
  { id: 2, name: 'Choi' },
  { id: 3, name: 'Park' }
];

// id가 2인 요소의 인덱스를 반환함
users.findIndex(user => user.id === 2); // -> 1

// name이 'Park'인 요소의 인덱스를 반환함
users.findIndex(user => user.name === 'Park'); // -> 3

 

Array.prototype.flatMap

  • flatMap 메서드는 map 메서드를 통해 생성된 새로운 배열을 평탄화함
  • map 메서드와 flat 메서드를 순차적으로 실행하는 효과가 있음
  • flatMap 메서드는 flat 메서드처럼 인수를 전달하여 평탄화 깊이를 지정할 수는 없고 1단계만 평탄화함
const arr = ['hello', 'world'];

arr.flatMap((str, index) => [index, [str, str.length]]);
// -> [[0, ['hello', 5]], [1, ['world', 5]]] => [0, ['hello', 5], 1, ['world', 5]]

arr.map((str, index) => [index, [str, str.length]]).flat(2);
// -> [[0, ['hello', 5]], [1, ['world', 5]]] => [0, 'hello', 5, 1, 'world', 5]

 

 

 

참고문헌 및 출처 : 모던 자바스크립트 Deep Dive (이웅모)

'JavaScript > 모던 자바스크립트 딥다이브' 카테고리의 다른 글

[JS] Math  (2) 2024.07.19
[JS] Number  (0) 2024.07.17
[JS] ES6 함수의 추가 기능  (0) 2024.07.01
[JS] 클래스  (2) 2024.06.13
[JS] 클로저  (0) 2024.06.02

댓글