강의 노트/JS

[JS deep dive] 배열

매망쩔 2023. 4. 14. 03:01

배열 : 여러 개의 값을 순차적으로 나열한 자료 구조

 

//배열리터럴로 만들기
const arr = ["apple", "banana"];
console.log(arr[0]); //apple

console.log(arr.length); //2

요소 : 배열이 가진 값

  • 배열의 요소는 자신의 위치를 나타내는 0이상의 정수인 인덱스를 갖는다.
  • 배열은 요소의 개수(배열의 길이)를 나타내는 length 프로퍼티를 가짐.
  • 배열은 객체 타입이다(배열 타입이란 존재 X)
  • 배열은 리터럴, Array 생성자 함수, Array.of, Array.from 메서드로 생성 가능
  • 배열의 프로토타입 객체는 Array.prototype으로 Array.prototype은 배열을 위한 빌트인 메서드를 제공함

배열과 객체의 차이점

구분 객체 배열
구조 프로퍼티 키와 값 인덱스와 요소
값의 참조 프로퍼티 키 인덱스
값의 순서 X O
length프로퍼티 X O

자바스크립트 배열은 배열이 아니다

일반적인 배열(밀집 배열)

자료구조에서 말하는 배열은 동일한 크기의 메모리 공간이 빈틈없이 연속적으로 나열된 자료구조를 말함.

배열의 요소는 하나의 데이터 타입으로 통일되어 있으며 서로 연속적으로 인접해 있음

 

자바스크립트 배열(희소 배열)

자바스크립트의 배열은 배열의 요소를 위한 각각의 메모리 공간이 동일한 크기를 갖지 않아도 되며, 연속적으로 이어져 있지 않을 수도 있다. 일반적인 배열의 동작을 흉내 낸 특수한 객체다

 

일반적인 배열과 자바스크립트 배열의 장단점

일반적인 배열은 인덱스로 요소에 빠르게 접근할 수 있다. 하지만 요소를 삽입 또는 삭제하는 경우에는 효율적이지 않다.

자바스크립트 배열은 해시 테이블로 구현된 객체이므로 인덱스로 접근하는 경우 일반적인 배열보다 성능적에서 느릴 수  밖에 없다. 하지만 요소를 삽입 또는 삭제하는 경우에는 일반적인 배열보다 빠른 성능을 기대할 수 있다.  

const arr = [];
console.time("Array Performance Test");

for (let i = 0; i < 10000000; i++) {
  arr[i] = i;
}
console.timeEnd("Array Performance Test"); //Array Performance Test: 159.333ms

const obj = {};

console.time("Object Performance Test");

for (let i = 0; i < 10000000; i++) {
  obj[i] = i;
}

console.timeEnd("Object Performance Test"); //Object Performance Test: 197.491ms

모던 자바스크립트 앤진은 배열을 일반 객체와는 구별하여 좀 더 배열처럼 동작하도록 최적화를 구현함

 

length 프로퍼티와 희소 배열

length 프로퍼티는 요소의 개수, 즉 배열의 길이를 나타내는 0 이상의 정수를 값으로 갖는다.

length 프로퍼티는 배열에 요소를 추가하거나 삭제하면 자동 갱신됨

length 프로퍼티 값은 요소의 개수 바탕으로 결정되지만 임의의  숫자 값을 명시적으로 할당할 수 있다.

 

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

// 현재 length 프로퍼티 값보다 작은 값을 할당
arr.length = 3;

//배열의 길이가 줌
console.log(arr); //[1,2,3]

const arr2 = [1, 2, 3, 4, 5];
arr2.length = 7;
console.log(arr2); //[ 1, 2, 3, 4, 5, <2 empty items> ]

 

length 값보다 큰 값을 할당한 경우 length 프로퍼티만 바뀌고 실제 값에는 영향 없음. 값 없이 비어 있는 요소를 위해 메모리 공간을 확보하지 않으며 빈 요소 생성하지도 않음.

 

희소 배열의 경우 length와 배열 요소 개수가 일치하지 않으며, length는 실제 요소 개수보다 언제나 크다.

모던 자바스크립트에선 최적화를 통해서 일반적인 의미의 배열처럼 생성하려 하므로, 희소 배열을 생성하지 않으려 하는게 좋다. 배열에는 같은 타입의 요소를 연속적으로 위치시키는 것이 최선임

 

배열 생성

1.배열 리터럴

 

//배열 리터럴
const arr = [1, 2, 3];

// 희소 배열
const arr2 = [1, , 2];
console.log(arr.length);
console.log(arr2[1]); //undefined

 

2. Array 생성자 함수

인수의 개수에 따라 다르게 작동함

 

# 전달된 인수가 1개고 숫자인 경우, length 프로퍼티 값이 인수인 배열 생성(희소배열)

#전달된 인수가 없는 경우 빈 배열 생성 === 배열 리터럴 []

# 전달된 인수가 2개 이상이거나 숫자가 아닌 경우 인수를 요소로 갖는 배열을 생성함

 

// 인수가 숫자 하나
new Array(10); // 희소 배열 [empty x 10]
// 인수가 여러개
new Array(1, 2, 3); //[1,2,3]

// 인수가 숫자가 아니면
new Array({}); // [{}]

 

3. Array of

ES6에서는 Array.of 로 전달된 인수를 요소로 갖는 배열을 생성 (인수가 1개이고순자더라도 배열 생성)

 

4. Array.form

 

유사 객체 또는 이터러블 객체를 인수로 전달받아 배열로 변환하여 반환함

//유사 배열 객체를 변환하여 배열을 생성함
Array.from({ length: 2, 0: "a", 1: "b" }); // ['a','b']

//이터러블을 반환하여 배열을 생성 (문자도 이터러블)
Array.from("Hey"); // ['H','e','y']

두 번쨰 인수로 콜뱀 함수를 통해 값을 만들면서 요소를 채울 수 있음. Array from 메서드는 두 번쨰 인수로 전달한 콜백 함수에 첫 번째 인수에 의해 생성된 배열의 요소값과 인덱스를 순차적으로 전달하면서 호출하고, 콜백 함수의 반환값으로 구성된 배열을 반환함.

//Array.from 에 length만 존재하는 유사 배열 객체를 전달하면 unefined 요소로 채움
Array.from({ length: 3 }); // [undefined,undefined,undefined]

//Array.form에 두 번쨰 인수로 전달ㄹ한 콜백 함수의 반환값으로 구성된 배열을 반환함
Array.from({ length: 3 }, (_, i) => i); //[0,1,2]

배열 요소의 참조

배열 요소를 참조할 때에는 [] 표기법을 사용함 (대괄호 안에는 인덱스)

인덱스는 값을 참조할 수 있다는 의미에서 객체의 프로퍼티 키와 같은 역할을 함.

 

const arr = [1, 2];

//인덱스가 0 인 요소
console.log(arr[0]); //1
// 존재하지 않는 요소에 접근
console.log(arr[2]); //undefined

// 희소 배열
const arr2 = [1, 2, , , 3];
console.log(Object.getOwnPropertyDescriptors(arr2));
// {
//     '0': { value: 1, writable: true, enumerable: true, configurable: true },
//     '1': { value: 2, writable: true, enumerable: true, configurable: true },
//     '4': { value: 3, writable: true, enumerable: true, configurable: true },
//     length: { value: 5, writable: true, enumerable: false, configurable: false }
//   }

배열 요소의 추가와 갱신

객체의 프로퍼티 동적 추가처럼, 배열에도 요소를 동적으로 추가할 수 잇음. 존재하지 않는 인덱스를 사용해 값을 할당하면 새로운 요소가 추가되고 length 프로퍼티 값이 갱신됨

존재 하는 요소에 값을 할당시 갱신됨

const arr = [0];
arr[1] = 1;
// 현재 배열의 length 프로퍼티값보다 큰 인덱스 요소 추가시 희소배열됨
arr[3] = 3;
console.log(arr); //[ 0, 1, <1 empty item>, 3 ]


arr[1] = 2;

console.log(arr); //[ 0, 2, <1 empty item>, 3 ]

 

정수 또는 정수 형태의 문자열 이외의 값을 인덱스 처럼 사용시 프로퍼티가 생성됨. 프로퍼티는 length 프로퍼티값에 영향 주지 않음

const arr = [];

// 배열 요소의 추가
arr[0] = 1;
arr[1] = 2;

//프로퍼티 추가
arr["foo"] = 3;
arr.bar = 4;
arr[1.1] = 5;
console.log(arr); //[ 1, 2, foo: 3, bar: 4, '1.1': 5 ]

console.log(arr.length); //2

 

배열 요소의 삭제

배열은 사실 객체이므로 delete 연산자를 사용하여 삭제 가능함.

하지만 delete 사용시 프로퍼티 영향을 주지 않아 희소 배열이 될 수 있음. 따라서 Array.prototype.splice 메서드를 사용하여 배열 특정 요소 삭제함.

 

배열 메서드

배열 메서드 중에서는 원본 배열을 직접 변경하는 메서드 와 원본 배열을 직접 변경하지 않고 새로운 배열을 반환하는 메서드가 있다

ex) push는 원본 배열을 직접 변경, concat은 새로운 배열을 생성해서 반환

 

#1 Array.isArray

Array.of와 Array.from 처럼 Array 생성자 함수의 정적 메서드.

전달된 인수가 배열이면 true 아니면 false를 반환함(유사 배열도 false)

 

Array.isArray({0:1,length:1}) //false

#2 Array.prototype.indexof

원본 배열에서 인수로 전달된 요소를 검색하여 인덱스를 반환

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

//foo배열에 'orange'요소 있는지 확인
console.log(foods.indexOf("oragne") === -1); //true
console.log(foods.includes("orange")); //false

#3 Array.prototype.push

push메서드는 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하고 변경된 length 프로퍼티값을 반환함. 

원본 배열을 직접 변경함

마지막에 하나의 값만 추가한다면 push보다 length 프로퍼티 사용해서 직접 추가하는게 성능이 좋음

const arr = [1, 2];
let result = arr.push(3, 4);
console.log("result : ", result, "arr : ", arr); //result :  4 arr :  [ 1, 2, 3, 4 ]

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

스프래드 문법을 사용하면 부수 효과 없이 배열 추가

 

#4 Array.prototype.pop

 

마지막 요소를 제거하고 제거한 요소를 반환함 (원본이 빈 배열이면  undefined 반환)

 

pop과 push 메서드를 이용하면 스택을 구현할 수 잇따 (후입 선출 방식의 자료 구조). 

 

 

const Stack = (function () {
  function Stack(array = []) {
    if (!Array.isArray(array)) {
      throw new TypeError(`${array}는배열이 아님`);
    }
    this.array = array;
  }
  Stack.prototype = {
    constructor: Stack,
    //스택의 가장 마지막에 데이터 넣음
    push(value) {
      return this.array.push(value);
    },
    // 마지막 데이터 꺼냄
    pop() {
      return this.array.pop();
    },
    entries() {
      return [...this.array];
    },
  };
  return Stack;
})();

const stack = new Stack([1, 2]);
console.log(stack.entries()); //[1,2]
console.log(stack.push(3)); //3
console.log(stack.pop()); //3

 

#5  Array.prototype.unshift

인수로 전달받은 모든 값을 원본 배열의 선두오 요소로 추가하고 변경된 length 프로퍼티 값을 반환함. 원본 배열을  직접 변경함

 

 

#6  Array.prototype.shift

원본 배열에서 첫 번째 요소를 제거하고 제거한 요소를 반환함. (빈배열이면 undefined반환),  원본을 직접 변경함

 

shift와 push를 사용하면 큐를 구현할 수 있따 (FIFO방식의 자료구조)

 

const Queue = (function () {
  function Queue(array = []) {
    if (!Array.isArray(array)) {
      throw new TypeError(`${array}는배열이 아님`);
    }
    this.array = array;
  }
  Queue.prototype = {
    constructor: Queue,
    //큐 가장 마지막에 데이터 넣음
    enqueue(value) {
      return this.array.push(value);
    },
    // 큐의 가장 처음 데이터 꺼냄 (먼저 넣은 것)
    dequeue() {
      return this.array.shift();
    },
    entries() {
      return [...this.array];
    },
  };
  return Queue;
})();

const queue = new Queue([1, 2]);
console.log(queue.entries()); //[1,2]
console.log(queue.enqueue(3)); //3
console.log(queue.dequeue()); //1
console.log(queue.entries()); //[ 2, 3 ]

#7 Array.prototype.concat

 

인수로 전달된 값들을 원본 배열의 마지막 요소로 추가한 새로운 배열을 반환함 (원본 변경 X)

인수 값이 배열인 경우 배열을 해체하여 새로운 배열의 요소로 추가함.

 

#8 Array.prototype.splice

원본을  직접 변경하며, 배열 중간에 요소를 추가하거나 제거할 때 사용

splice 는 3갬의 매개변수가 있음

start : 원본 배열의 요소를 제거하기 시작할 인덱스 , start가 음수인 경우 배열의 끝에서의 인덱스를 나타냄(-1이면 마지막)

deleteCount : 원본 배열의 요소를 제거하기 시작할 인덱스인 start부터 제거할 요소의 개수 (0이면 아무것도 삭제 안됨)

items : 제거한 위치에 삽입할 요소들의 목록 (옵션)

 

 

const arr = [1, 2, 3, 4];

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

//제거한 요소 반환
console.log(result); //[ 2, 3 ]
//원본 훼손
console.log(arr); //[ 1, 20, 30, 4 ]

3번쨰 요소는 생략가능하고, 두 번쨰 요소 생략시 첫 번쨰 인수로 부터 모든 요소를 제거함.

 

#9 Array.prototype.splice

두 개의  매개 변수를 갖고 원본을 훼손하지 않음

인수로 전달된 범위의 요소들을 복사하여 배열로 반환함

두 번째 인수 생략시 첫 번쨰 인수로 전달받은 인덱스로부터 모든 요소를 복사하여 배열로 반환함.

slice로 생성된 복사본은 얕은 복사를 통해 생성됨

const todos = [
  { id: 1, content: "굿" },
  { id: 2, content: "구웃" },
  { id: 3, content: "꾸웃" },
];

//얕은 복사
const _todos = todos.slice();
console.log(_todos === todos); // 별개의 객체임 false

// 배열요소의 참조값이 같음 (얕은 복사)
console.log(_todos[0] === todos[0]); //true

 

#10 Array.prototype.join

원본 배열의 모든 요소를 문자열로 변환한 수 , 인수로 전달받은 문자열 즉 구분자로연결한 문자열을 반환함

구분자 생략시 ,(콤마)

 

const arr = [1, 2, 3, 4];

// 기본 구분자 콤마
arr.join();
console.log(arr.join()); //1,2,3,4

console.log(arr.join(" ")); //1 2 3 4

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

#11 Array.prototype.reverse

원본 배열의 순서를 반대로 뒤집음. 이때 원본 배열이 변경됨

 

#12 Array.prototype.fill

 

인수로 전달 받은 값을 배열의 처음부터 끝까지 요소로 채움 ( 원본 배열 변경)

 

const arr = [1, 2, 3];
arr.fill(0);
console.log(arr); //[ 0, 0, 0 ]

두 번쨰 인수로 요소 채우기를 시작할 인덱스 선택 가능

세 번쨰 인수로 멈출 인덱스 선택 가능

모든 요소를 하나의 값으로만 채울수 밖에 없음

 

#13  Array.prototype.includes

 

ES7에 도입된 배열내에  특정 요소가 포함되어 있는지 확인하여 true 또는 false 반환함

첫 번쨰 인수로 검색 대상 지정, 두 번쨰 인수로 검색을 시작할 인덱스 전달 (기본값 0 음수 시 length+index로 시작 인덱스 설정) 

 

#14. flat

ES10에서 도입된 flat 메서드는 인수로 전달한 깊이만큼 재귀적으로 배열을 평탄화 함

인수로 Infinity를 전달하면 중첩 배열을 모두 평탄화함

const flat0 = [1, [2, [3, [4]]]].flat();
const flat2 = [1, [2, [3, [4]]]].flat(2);
console.log(flat0); //[ 1, 2, [ 3, [ 4 ] ] ]

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

 

배열 고차 함수

 고차 함수는 함수를 인수로 전달받거나 함수를 반환하는 함수를 말함. 고차 함수는 외부 상태의 변경이나 가변 데이터를 피하고 불변성을 지향하는 함수형 프로그래밍에 기반을 두고 있음.

함수형 프로그래밍은 순수 함수와 보조 함수의 조합을 통해 로직 내에 존재하는 조건문과 반복문을 제거하고 복잡성을 해결하고 변수의 사용을 억제하여 상태 변경을 피하려는 프로그래밍 페러다임이다

순수 함수를 통해 부수 효과를 최대한 억제하고 오류를 피하고 프로그램의 안정성을 높이려는 노력의 일환

 

#1 Array.prototype.sort

sort 메서드는 배열의요소를 정렬함 (원본 배열을 직접 변경함) 

내림 차순은 sort 후에 reverse 메서드를 이용해서 뒤집음

 

 

이때 유니코드 코드 포인트를 따른다. 따라서 100 < 2

const points = [40, 2, 100, 1, 20, 11];
console.log(points.sort()); //[ 1, 100, 11, 2, 20, 40 ]

따라서 숫자 요소 정렬할 떄는 sort 메서드에 정렬 순서를 정의하는 비교 함수를 인수로 전달해야 함

 

const points = [40, 2, 100, 1, 20, 11];
console.log(points.sort()); //[ 1, 100, 11, 2, 20, 40 ]

const points2 = [40, 2, 100, 1, 20, 11];
console.log(points2.sort((a, b) => a - b)); //[ 1, 2, 11, 20, 40, 100 ]

객체를 요소로 갖는 배열을 정렬하는 방법

const todos = [
  { id: 4, content: "JavaScript" },
  { id: 1, content: "HTML" },
  { id: 2, content: "CSS" },
];

//비교 함수, 매개변수 key는 프로퍼티 키다.
function compare(key) {
  //프로퍼티 값이 문자열인 경우 -산술 연산으로 비교하면 NaN이 나오므로 비교 연산을 사용한다.
  // 비교 함수는 양수 음수 /0을 반환하면 되므로 - 산술 연산 대신 비교 연산을 사용할 수 있다.
  return (a, b) => (a[key] > b[key] ? 1 : a[key] < b[key] ? -1 : 0);
}

//id를 기준으로 오름차순 정렬
todos.sort(compare("id"));
console.log(todos);

// [
//     { id: 1, content: 'HTML' },
//     { id: 2, content: 'CSS' },
//     { id: 4, content: 'JavaScript' }
//   ]

//content 기준으로 오름차순 정렬
todos.sort(compare("content"));
console.log(todos);

//[
//     { id: 2, content: 'CSS' },
//     { id: 1, content: 'HTML' },
//     { id: 4, content: 'JavaScript' }
//   ]

#2 Array.prototype.forEach

조건문과 반복문을 제거하여 복잡성을 해결하고 변수의 사용을 억제하여 상태 변경을 피하려는 프로그래밍 패러다임.

const numbers = [1, 2, 3];
const pows = [];

//for 문으로 배열 순회
for (let i = 0; i < numbers.length; i++) {
  pows.push(numbers[i] ** 2);
}

console.log(pows); //[ 1, 4, 9 ]

const numbers2 = [1, 2, 3];
const pows2 = [];

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

for문은 반복을 위한 변수를 선언해야하는데, 조건식과 증감식으로 이루어져서 함수형 프로그래밍이 추구하는 바와 맞지 않음

forEach 메서드의 콜백함수는 forEach 메서드를 호출한 배열의 요소값과 인덱스, forEach 메서드를 호출한 배열 자체 , 즉 this를 순차적으로 전달받을 수 있다. 다시 말해, forEach 메서드는 콜백 함수를 호출할 때 3개의 인수, 즉 forEach 메서드를 호출한 배열의 요소값과 인덱스 , forEach 메서드를 호출한 배열을 순차적으로 전달함.

 

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

// 요소값을: 1, 인덱스: 0, this: [1,2,3]
// 요소값을: 2, 인덱스: 1, this: [1,2,3]
// 요소값을: 3, 인덱스: 2, this: [1,2,3]

forEach 메서드는 원본 배열을 변경하지는 않지만, 콜백함수를 통해 변경할 수는 있음

forEach 메서드의 반환값은 언제나 undefined이다.

forEach메서드의  두 번쨰 인수로 forEach 메서드의 콜백 함수 내부에서 this로 사용할 객체를 전달할 수 있다.

class Numbers {
  numberArray = [];

  multiply(arr) {
    arr.forEach(function (item) {
      this.numberArray.push(item * item);
    }, this);
  }
}

const numbers = new Numbers();
numbers.multiply([1, 2, 3]);
console.log(numbers.numberArray); //[ 1, 4, 9 ]

   forEaCH는 반복문을 통해 배열을 순회하나,  반복문을 메서드 내부로 은닉하여 로직의 흐름을 이해하기 쉽게 하고 복잡성을 해결한다. 하지만 for문과는 달리 break, continue 문을 사용할 수 없다.

희소 배열의 경우 존재하지 않는 요소는 순회 대상에서 제외된다 (map, filter, reduce도 동일함.)

for문에 비해 성능이 좋지는 않지만 가독성이 좋다..

 

#3. Array.prototype.map

 

map 메서드는 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출한다. 그리고 콜백 함수의 반환값들로 구성된 새로운 배열을 반환한다. ( 원본 배열 호ㅞ손 x)

(forEach는 undefined를 반환하는 것과는 다름)

 

map 메서드가 생성하여 반환하는 새로운 배열의 length 프로퍼티 값은 map 메서드를 호출한 배열의 length 프로퍼티 값과 반드시 일치한다. 즉 map 메서드를 호출한 배열과 map 메서드가 생성하여 반환한 배열은 1:1 매핑한다.

forEach 메서드와 마찬가지로 map 메서드의 두 번째 인수로 map 메서드의 콜백 함수 내부에서 .this로 사용할 객체를 전달할 수 있다. 

화살표 함수를 사용시 굳이 전달 안해도 됨.(화살표 함수는 상위 스코프 this를 참조하니깐)

class Prefixer {
  constructor(prefix) {
    this.prefix = prefix;
  }

  add(arr) {
    //화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 참조한다
    return arr.map((item) => this.prefix + item);
  }
}

const prefixer = new Prefixer("-webkit-");
console.log(prefixer.add(["transition", "user-select"])); //[ '-webkit-transition', '-webkit-user-select' ]

#4 Array.prototype.filter

 자신을 호출한 배열의 모든 요소를 순회하면서 인수로 전달받은 콜백 함수를 반복 호출한다. 콜백 함수의 반환값이 true인 요소로만 구성된 새로운 배열을 반환한다. 원본은 변경되지 않는다.

filter 메서드가 생성하여 반환한 새로운 배열의 lnegth 프로퍼티 값은 filter 메서드를 호출한 배열의 length 프로퍼티 이하다

filter 메서드는 콜백함수를 호출하면서 3개의 인수를 전달할 수 있다(요소값, 인덱스 ,this) 또한 두 번쨰 인수로 this 전달할 수 도 잇따.

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

filter 메서드는 자신을 호출한 배열에서 특정 요소를 제거하기 위해서 사용 가능

filter 메서드를 사용해서 제거시 특정 요소가 중복되어 있다면 중복된 요소가 모두 제거된다.

 

class Users {
  constructor() {
    this.users = [
      { id: 1, name: "Lee" },
      { id: 2, name: "Kim" },
    ];
  }
  //요소 추출
  findById(id) {
    //id 가 일치하는 사용자만 반환한다.
    return this.users.filter((user) => user.id === id);
  }

  //요소 제거
  remove(id) {
    //id가 일치하지 않는 사용자 제거
    this.users = this.users.filter((user) => user.id !== id);
  }
}

const users = new Users();

let user = users.findById(1);
console.log(user); // [ { id: 1, name: 'Lee' } ]

//id가 1인 사용자를 제거한다.
users.remove(1);

user = users.findById(1);
console.log(user); //[]

 

#5 Array.prototype.reduce

자신을 호출한 배열을 모든 요소로 순회하며 인수로 전달받은 콜백 함수를 반복호출한다. 그리고 콜백 함수의 반환값을 담음 순회 시에 콜백 함수의 첫 번쨰 인수로 전달하면서 콜백 함수를 호출하여 하나의 결과값을 만들어 반환한다. 이때 원본 배열은 변경되지 않는다.

reduce 메서드는 첫 번째 인수로 콜백함수, 두 번쨰 인수로는 초기값을 전달받는다. rreduce 메서드의 콜백 함수에는 4개의 인수, 초기값 또는 콜백 함수의 이전 반환값, reduce 메서드를 호출한 배열의 요소값과 인덱스, reduce 메서드를 호출한 배열 자체가 전달된다.

//1부터 4까지 누적한다
const sum = [1, 2, 3, 4].reduce(
  (accumulator, currentValue, index, array) => accumulator + currentValue,
  0
);

console.log(sum); //10
구분  콜백 함수에 전달되는 인수 콜백 함수의 반환값
accumulator currentValue Index array
첫 번째 0 1 0 [1,2,3,4] 1
두 번째 1 2 1 [1,2,3,4]

3
세 번째 3 3 2 [1,2,3,4]

6
네 번째 6 4 3 [1,2,3,4]

10

reduce 메서드는 하나의 결과값을 반환함.

활용법

평균 구하기, 최대값 구하기, 요소의 중복 횟수 구하기,

중첩 배열의 평탄화 (ES10 부터는 flat 사용 가능)

중복 요소의 제거(filter가 더 직관적임)

map , filter, some , every, find같은 고차함수는 reduce 메서드로 구할 수 있음.

reduce의 두 번쨰 인수로 전달하는 초기값은 옵션이나 전달하는 것이 안전함.

객체의 프로퍼티값의 합을 구할때도 초기값을 설정하면 애러 안뜸

 

#6. Array.prototype.some

 

some 메서드는 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백함수를 호출한다. 이때 some 메서드는 콜백 함수의 반환값이 단 한 번이라도 참이면 true , 모두 거짓이면 false를 바노한함. 

// 배열의 요소 중 10보다 큰 요소가 1개 이상 존재하는지 확인
console.log([5, 10, 15].some((item) => item > 10)); //true

 

#7. Array.prototype.every

every 메서드는 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출한다. 이떄 every 메서드는 단 한번이라도 거짓이면 false를 반환한다(some 반대)

 

#8.Array.prototype.find

ES6 에서 도입된 find 메서드는 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출하여 반환값이 true인 첫 번쨰 요소를 반환한다. 콜백 함수의 반환값이 true인 요소가 존재하지 않는 다면 undefined를 반환한다.

 

#9. .Array.prototype.findIndex

 

ES6 에서 도입된 findInex 메서드는 자신을 호출한 배열의 요소를 순회하면서 인수로 전달된 콜백 함수를 호출하여 반환값이 true인 첫 번쨰 요소의 인덱스를 반환한다. 콜백 함수의 반환값이 true인 요소가 존재하지 않는 다면 -1을 반환한다.

 

const users = [
  { id: 1, name: "lee" },
  { id: 2, name: "kim" },
  { id: 3, name: "choi" },
];

console.log(users.findIndex((user) => user.id === 2)); //1
console.log(users.find((user) => user.id === 2)); //{ id: 2, name: 'kim' }

#10. Array.prototype.flatMap

ES10 도입된 flatMap 메서드는 map 메서드를 통해 생성된 새로운 배열을 평탄화한다. 즉 map 메서드와 flat 메서드를 순차적으로 실행한 효과가 있고, flat 메서드처럼 인수를 전달하여 평탄화 깊이를 지정할 수는 없고 1단계만 ㅕㅇ탄화 한다.

const arr = ["hello", "world"];

//map과 flat 을 순차적으로 실행
console.log(arr.map((x) => x.split("")).flat());
// [
//     'h', 'e', 'l', 'l',
//     'o', 'w', 'o', 'r',
//     'l', 'd'
//   ]

'강의 노트 > JS' 카테고리의 다른 글

[JS deep dive] Math  (0) 2023.04.16
[JS deep dive] Number  (0) 2023.04.16
[JS deep dive] ES6 함수의 추가 기능  (0) 2023.04.11
[JS deep dive] 25장 클래스  (0) 2023.04.10
[JS deep dive] 클로저  (0) 2023.04.07