자바스크립트 배열 메서드

Yun·2024년 6월 14일
0

Array

자바스크립트 배열은 다양한 데이터 타입의 값을 포함할 수 있는 동적 배열이다.

// 각 요소는 서로 다른 데이터 타입을 가질 수 있다.
const array = [123, 'name', true, function () { }, {}, ['a', 'b']];
    
// 배열의 이름은 복수형으로 짓는 게 일반적이다.
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.length); // 5
console.log(numbers[0]); // 1

추가/삭제

index

인덱스를 사용해 새로운 요소를 추가한다. 빈 자리는 empty items로 채워진다.

const numbers = [0, 1, 2];

numbers[numbers.length] = 3; // [0, 1, 2, 3]
numbers[10] = 10; // [0, 1, 2, 3, <6 empty items>, 10]

push, unshift

push()는 배열의 끝에 새로운 요소를 추가하고, unshift()는 배열의 앞에 새로운 요소를 추가한다. 두 개 이상의 값을 한 번에 넣을 수도 있다.

const numbers = [0, 1, 2];

numbers.push(3); // [0, 1, 2, 3]
numbers.push(4, 5); // [0, 1, 2, 3, 4, 5]

numbers.unshift(-1); // [-1, 0, 1, 2]
numbers.unshift(-3, -2); // [-3, -2, -1, 0, 1, 2]

concat

concat()은 두 개 이상의 배열을 결합하거나 배열에 값을 추가할 수 있다.

push(), unshift()와 다르게 완전히 새로운 배열을 반환하며, 기존 배열은 변경되지 않는다.

const nums1 = [0, 1];
const nums2 = [2, 3];
	
const nums3 = nums1.concat(nums2);
// [0, 1, 2, 3]
const nums4 = nums3.concat(nums1, nums2);
// [0, 1, 2, 3, 0, 1, 2, 3]
const nums5 = nums1.concat(10);
// [0, 1, 10]

splice

splice()는 배열의 내용을 변경하고, 제거된 요소가 담긴 별도의 배열을 새로 반환한다.

Array.splice(start, deleteCount, newItem, newItem, ...)

start : 변경을 시작할 인덱스
deleteCount : 제거할 요소의 수
newItem : 배열에 추가할 요소 (지정하지 않으면 제거만 한다.)

const original = [0, 1, 2];

const spliced = original.splice(0, 2);
console.log(original); // [2]
console.log(spliced); // [0, 1]

const spliced = original.splice(1, 0, 'new');
console.log(original); // [0, 'new', 1, 2]
console.log(spliced); // []

pop

pop()은 배열의 마지막 요소를 제거하고 반환한다.

const numbers = [0, 1, 2];
const popped = numbers.pop();

console.log(numbers); // [0, 1]
console.log(popped); // 2

slice

slice()는 배열의 일부를 추출하여 새로운 배열로 반환한다.

const numbers = [0, 1, 2];

const sliced = numbers.slice(1);
console.log(sliced); // [1, 2]

const sliced = numbers.slice(0, 1);
console.log(sliced); // [0]

탐색/확인

indexOf, lastIndexOf

indexOf()는 특정 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고,lastIndexOf()는 마지막 인덱스를 반환한다. 찾을 수 없는 경우엔 -1를 반환한다.

Array.indexOf(searchElement, fromIndex = 0);
Array.lastIndexOf(searchElement, fromIndex = this.length - 1);

searchElement : 찾는 요소
fromIndex : 검색을 시작할 인덱스

const numbers = [0, 1, 2, 0, 1, 2];

console.log(numbers.indexOf(1)); // 1
console.log(numbers.lastIndexOf(1)); // 4

console.log(numbers.indexOf(2, 3)); // 5
console.log(numbers.lastIndexOf(2, 3)); // 2

console.log(numbers.indexOf(5)); // -1
console.log(numbers.lastIndexOf(5)); // -1

find, findIndex

find()는 각 요소에 콜백 함수를 실행하여 첫 번째로 true를 반환한 요소를 반환한다. findIndex()는 요소의 인덱스를 반환한다. 찾을 수 없는 경우엔 -1를 반환한다.

indexOf 보다 복잡한 조건을 사용하여 요소를 찾아야 할 때 사용한다. 객체 배열에서 특정 속성을 가진 요소를 찾는 데 유용하게 쓸 수 있다.

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

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


function isPark(element) {
  if (element.name === 'park') {
    return true;
  }
}
const park = users.find(isPark);
console.log(park); // { id: 3, name: 'park' }


const userIndex = users.findIndex(user => user.id === 2);
console.log(userIndex); // 1

includes

includes()는 배열에 특정 값이 포함되어 있는지 확인한다. 포함되어 있으면 true를, 포함되어 있지 않으면 false를 반환한다.

Array.includes(searchElement, fromIndex);

searchElement : 찾는 요소
fromIndex : 검색을 시작할 인덱스

const numbers = [0, 1, 2];

console.log(numbers.includes(1)); // true
console.log(numbers.includes(5)); // false

const numbers = [0, NaN, 2];
console.log(numbers.includes(NaN)); // true

순환

forEach

forEach()는 배열의 요소를 순회하며 제공된 함수를 실행한다. 별도의 반환값은 없다.

const numbers = [1, 2, 3];

numbers.forEach(num => console.log(num)); // 1, 2, 3

const double = [];
numbers.forEach(num => double.push(num * 2));
console.log(double); // [2, 4, 6]

map

map()은 배열의 각 요소를 순회하며 제공된 함수를 실행하고, 그 결과로 새로운 배열을 생성한다.

const numbers = [1, 2, 3];

const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6]

const string = numbers.map(num => num.toString());
console.log(string); // ['1', '2', '3']

const info = numbers.map((num, index) => ({
  value: num,
  index: index
}));
console.log(info);
// [
//   { value: 1, index: 0 },
//   { value: 2, index: 1 },
//   { value: 3, index: 2 },
//   { value: 4, index: 3 },
//   { value: 5, index: 4 }
// ]

reduce

reduce()는 배열의 각 요소를 순회하면서 누적 값을 계산한다. 새로운 배열을 생성하는 map()과 다르게 단일 값을 생성한다.

Arr.reduce(callback, initialValue);

callback: 각 요소에 처리할 함수이다. 네 가지 인수를 받을 수 있다.

  • accumulator : 이전 호출의 반환값
  • currentValue : 현재 처리 중인 요소
  • (선택) currentIndex : 현재 처리 중인 요소의 인덱스
  • (선택) array : 원본 배열

initialValue : 초기 acc값 (생략하면 첫 번째 요소가 초기값이 된다.)

// 합계 구하기
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 15


// 요소 개수 세기
const fruits = ['apple', 'banana', 'cherry', 'banana'];
const fruitCount = fruits.reduce((count, fruit) => {
  count[fruit] = (count[fruit] || 0) + 1;
  return count;
}, {});
console.log(fruitCount); // { apple: 1, banana: 2, cherry: 1 }


// 중첩 해제하기
const nestedArray = [[1, 2], [3, 4], [5, 6]];
const flatArray = nestedArray.reduce((acc, cur) => acc.concat(cur), []);
console.log(flatArray); // [1, 2, 3, 4, 5, 6]

some, every

some()은 배열의 요소 중 하나라도 테스트 함수를 통과하면 true를 반환한다. every()는 배열의 모든 요소가 테스트 함수를 통과했을 때 true를 반환한다.

const numbers = [1, 2, 3];

const negativeNum = numbers.some(num => num < 0); // false
const evenNum = numbers.some(num => num % 2 === 0); // true

const positiveAll = numbers.every(num => num > 0); // true
const evenAll = numbers.every(num => num % 2 === 0); // false

배열이 비어있을 때, some은 false를 반환하고 every는 true를 반환한다.

filter

filter()은 배열의 각 요소를 순회하며 제공된 함수를 실행하고, 그 결과가 true인 요소만 모은 새로운 배열을 반환한다.

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const even = numbers.filter(num => num % 2 === 0);
console.log(even); // [2, 4, 6, 8, 10]

const largerThanFive = numbers.filter(num => num > 5);
console.log(largerThanFive); // [6, 7, 8, 9, 10]

변형

reverse

reverse()는 배열의 순서를 반대로 변경한다.

const numbers = [0, 1, 2];
const reversed = numbers.reverse();

console.log(numbers); // [2, 1, 0]
console.log(reversed); // [2, 1, 0]

sort

sort()는 배열의 요소를 정렬한다. 기준을 사용자가 정의할 수도 있다.

const numbers = [5, 2, 9, 1, 7];
numbers.sort(); // [1, 2, 5, 7, 9]

// 오름차순, 내림차순
numbers.sort((a, b) => a - b); // [1, 2, 5, 7, 9]
numbers.sort((a, b) => b - a); // [9, 7, 5, 2, 1]

// 문자열 배열 정렬
const strings = ['banana', 'apple', 'cherry', 'date'];
strings.sort(); // ['apple', 'banana', 'cherry', 'date']

// 객체 배열 정렬
const people = [
  { name: 'Kim', age: 21 },
  { name: 'Lee', age: 54 },
  { name: 'Park', age: 36 }
];

people.sort((a, b) => a.age - b.age);
// [
//   { name: 'Charlie', age: 20 },
//   { name: 'Alice', age: 25 },
//   { name: 'Bob', age: 30 }
// ]

문자열

toString

toString()은 배열의 모든 요소를 하나의 문자열로 변환하여 반환한다. 각 요소는 쉼표로 구분되며, 원본 배열은 변경되지 않는다.

const numbers = [0, 1, 2];
const string = numbers.toString(); // "0,1,2"

join

join()은 각 요소 사이에 지정된 구분자를 삽입하여 문자열로 변환할 수 있다. 지정하지 않으면 기본적으로 쉼표로 구분된다.

const numbers = [0, 1, 2];
const result1 = numbers.join(); // "0,1,2"
const result2 = numbers.join('-'); // "0-1-2"

얕은 복사

새로 생성된 배열은 얕은 복사라는 점을 주의하자.

const original = [{ name: 'kim' }, [1, 2]];
const copied = original.concat();

copied.push(3);
copied[0].name = 'lee';
original[1].push(3);

console.log(original); // [{ name: 'lee' }, [1, 2, 3]]
console.log(copied);  // [{ name: 'lee' }, [1, 2, 3], 3]

얕은 복사가 드러나는 대표적인 데이터 타입은 다음과 같다.

  • 객체 리터럴({})
  • 배열 리터럴([])
  • 함수 리터럴(Function() {...})
  • Date, RegExp, Error 등의 내장 객체

반면에 다음과 같은 타입은 참조 타입이 아닌 값 타입이기 때문에 깊은 복사가 된다.

  • number, string, boolean, undefined, null

따라서 배열이나 객체에 값 타입 데이터만 포함되어 있다면 복사 시 얕은 복사가 발생하지 않는다. 하지만 참조 타입이 포함되어 있다면 반드시 얕은 복사가 일어난다.

배열을 깊은 복사 하기 위해선 JSON 변환을 이용하면 된다. JSON.stringify()를 사용해 배열을 문자열로 변환한 후, JSON.parse()로 다시 배열로 변환하는 방식이다.

let original = [1, { a: 2 }, [3, 4]];
let copied = JSON.parse(JSON.stringify(original));

0개의 댓글