Array

배열의 기초

  • 배열은 객체와 달리 본질에서 순서가 있는 데이터 집합이며 0 으로 시작하는 숫자형 인덱스를 사용한다.
  • 자바스크립트의 배열은 비균질적이다. 즉, 한 배열의 요소가 모두 같은 타입일 필요는 없다. 배열은 다른 배열이나 객체도 포함할 수 있다.
  • 배열 리터럴은 대괄호로 만들고, 배열 요소에 인덱스로 접근할 때도 대괄호를 사용한다.
  • 모든 배열에는 요소가 몇 개 있는지 나타내는 lengh 프로퍼티가 있다.
  • 배열에 모든 배열 길이보다 큰 인덱스를 사용해서 요소를 할당하면 배열은 자동으로 그 인덱스에 맞게 늘어나며, 빈자리는 undefined 로 채워진다.
// 배열 리터럴
const arr1 = [1, 2, 3] // 숫자로 구성된 배열
const arr2 = ['one', 2, 'three'] // 비균질적 배열
const arr3 = [[1, 2, 3], ['one', 2, 'three']] //배열을 포함한 배열
const arr4 = [
  { name: 'Sun', type: 'object', birth: '920412' },
  function() {
    return 'Hello World'
  },
  1
] // 비균질적 배열

// 배열 요소에 접근
arr1[0] // 1
arr3[1] // ['one', 2, 'three']
arr3[1][2] // three

// 배열 길이
arr1.length // 3
arr3[1].length // 3

// 배열 길이 늘리기
arr1[4] = 5
arr1 // [1,2,3,undefined,5]
arr1.length // 5

// 배열의 현재길이보다 큰 인덱스에 접근하는 것으로는 배열의 길이가 늘어나지 않는다
arr2[10] // undefined
arr2.length // 3

배열 요소 조작

배열의 처음이나 끝에서 요소를 추가하거나 제거하기

push 와 pop 은 데이터를 수직으로 쌓아올리는 stack 에 해당하는 행동이다. shift 와 unshift 는 대기열과 비슷한 queue 에 해당하는 행동이다.

const arr = ['b', 'c', 'd']
arr.push('e') // 4
arr // ["b", "c", "d", "e"]
arr.pop() // "e"
arr // ["b", "c", "d"]
arr.unshift('a') // 4
arr // ["a", "b", "c", "d"]
arr.shift() // "a"
arr // ["b", "c", "d"]

배열의 끝에 여러 요소 추가하기

concat 메서드는 배열의 끝에 여러 요소를 추가한 사본을 반환한다. 즉, 원래의 배열은 바뀌지 않는다.

const arr = [1, 2, 3]
arr.concat(4, 5, 6) // [1,2,3,4,5,6]
// arr는 변하지 않음
arr // [1, 2, 3]
arr.concat([4, 5, 6]) // [1,2,3,4,5,6]
arr.concat([4, 5], 6) // [1,2,3,4,5,6]
arr.concat(4, [5, 6]) // [1,2,3,4,5,6]

배열 일부 가져오기

slice 메서드는 두개의 매개변수를 받는다. 첫 번째는 어디서부터 가져올지를, 두 번째는 어디까지 가져올지를 지정한다. 두 번째 매개변수를 생략하면 배열의 마지막까지 반환한다. 매개변수는 음수 인덱스를 쓸 수 있다.

const arr = [1, 2, 3, 4, 5]
arr.slice(3) // [4,5]
// arr는 변하지 않음
arr // [1, 2, 3, 4, 5]
arr.slice(2, 4) // [3,4]
arr.slice(-2) // [4,5]
arr.slice(1, -2) // [2,3]
arr.slice(-2, -1) // [4]

임의의 위치에 요소 추가하거나 제거하기

splice 는 배열을 수정할 수 있다. 첫 번째 매개변수는 수정을 시작할 인덱스이고, 두 번째 매개변수는 제거할 요소 숫자이다. 아무 요소도 제거하지 않을경우 0 을 넘겨주면 된다. 나마지 매개변수는 배열에 추가할 요소이다.

const arr = [1, 5, 7]
arr.splice(1, 0, 2, 3, 4) // []
arr // [1, 2, 3, 4, 5, 7]
arr.splice(5, 0, 6) // []
arr // [1, 2, 3, 4, 5, 6, 7]
arr.splice(1, 2) // [2,3]
arr // [1, 4, 5, 6, 7]
arr.splice(2, 1, 'a', 'b') // [5]
arr // [1, 4, "a", "b", 6, 7]

배열 안에서 요소 교체하기

copyWithin 은 배열 요소를 복사해서 다른 위치에 붙여넣고, 기존의 요소를 덮어쓴다. 첫 번째 매개변수는 복사한 요소를 붙여넣을 위치이고, 두 번째 매개변수는 복사를 시작할 위치이고, 세 번째 매개변수는 복사를 끝낼 위치이다. splice 와 마찬가지로 음수 인덱스를 사용할 수 있다.

const arr = [1, 2, 3, 4]
arr.copyWithin(1, 2) // [1, 3, 4, 4]
arr.copyWithin(2, 0, 2) // [1, 3, 1, 3]
arr.copyWithin(0, -3, -1) // [3, 1, 1, 3]

특정 값으로 배열 채우기

fill 은 정해진 값으로 배열을 채워준다. 배열의 일부만 채우려 할 때는 시작 인덱스와 끝 인덱스를 지정하면 된다. 음수 인덱스도 사용 가능하다.

const arr = new Array(5).fill(1)
arr // [1, 1, 1, 1, 1]
arr.fill('a') // ["a", "a", "a", "a", "a"]
arr.fill('b', 1) // ["a", "b", "b", "b", "b"]
arr.fill('c', 2, 4) // ["a", "b", "c", "c", "b"]
arr.fill(5.5, -4) // ["a", 5.5, 5.5, 5.5, 5.5]
arr.fill(0, -3, -1) // ["a", 5.5, 0, 0, 5.5]

배열 정렬과 역순 정렬

const arr = [1, 2, 3, 4, 5]
arr.reverse() // [5, 4, 3, 2, 1]
arr.sort() // [1, 2, 3, 4, 5]

배열 검색

indexOf 를 사용하여 찾고자 하는 것과 정확히 일치하는 첫 번째 요소의 인덱스를 가져올 수 있다. lastIndexOf 는 배열의 끝에서 부터 검색한다. 배열의 일부분만 검색하고 싶으면 시작인덱스를 지정할 수 있다. 일치하는 값이 없으면 -1 을 반환한다.

const o = { name: 'SunLee' }
const arr = [1, 5, 'a', o, true, 5, [1, 2], '9']
arr.indexOf(5) // 1
arr.lastIndexOf(5) // 5
arr.indexOf('a') // 2
arr.lastIndexOf('a') // 2
arr.indexOf(o) // 3
arr.indexOf([1, 2]) // -1
arr.indexOf('9') // 7
arr.indexOf(9) // -1

arr.indexOf('a', 5) // -1
arr.indexOf(5, 5) // 5
arr.lastIndexOf(5, 4) // 1
arr.lastIndexOf(true, 3) // -1

findIndex 는 일치하는 값을 찾지 못하였을때 -1 을 반환한다는 점에서는 indexOf 와 비슷하지만, 보조 함수를 써서 검색 조건을 지정할 수 있다. 하지만, findIndex 는 시작 인덱스를 지정할 수도 뒤에서부터 시작할 수도 없다.

const arr = [{ id: 5, name: 'Sun' }, { id: 7, name: 'Lee' }]
arr.findIndex(o => o.id === 5) // 0
arr.findIndex(o => o.name === 'Lee') // 1
arr.findIndex(o => o === 3) // -1
arr.findIndex(o => o.id === 14) // -1

조건의 맞는 요소의 index 가 아닌 요소 자체를 원할 경우에는 find 를 사용한다. 조건에 맞는 요소가 없을 때는 undefined 를 반환한다.

const arr = [{ id: 5, name: 'Sun' }, { id: 7, name: 'Lee' }]
arr.find(o => o.id === 5) // {id: 5, name: "Sun"}
arr.find(o => o.id === 2) // undefined

some 은 조건에 맞는 요소를 찾으면 검색을 멈추고 true 를 반환하며, 그렇지 않으면 false 를 반환한다.

const arr = [5, 7, 12, 15, 17]
arr.some(x => x % 2 === 0) // true; 12는 짝수
arr.some(x => Number.isInteger(Math.sqrt(x))) // false; 제곱수가 없다.

every 는 배열의 모든 요소가 맞을경우 true 를 반환하며, 그렇지 않으면 false 를 반환한다.

const arr = [4, 6, 16, 36]
arr.every(x => x % 2 === 0) // true
arr.every(x => Number.isInteger(Math.sqrt(x))) // false; 6은 제곱수가 아니다.

map 과 filter

map 은 배열 요소를 변형한다. 일정한 형식의 배열을 다른 형식으로 바꿔야 할 경우에 map 을 사용한다.

const cart = [{ name: 'Widget', price: 9.95 }, { name: 'Gadget', price: 22.95 }]
const names = cart.map(x => x.name) // ["Widget", "Gadget"]
const prices = cart.map(x => x.price) // [9.95, 22.95]
const discountPrices = prices.map(x => x * 0.8) // [7.96, 18.36]
const list = names.map((x, i) => ({ name: x, price: prices[i] })) // [{name: 'Widget', price: 9.95},{name: "Gadget, price: 22.95}]

filter 를 사용하면 배열에서 필요한 것들만 남길 수 있습니다.

// 카드 덱 만들기
const cards = []
// 하트, 클로버, 다이아몬드, 스페이드
for (let suit of ['H', 'C', 'D', 'S']) {
  for (let value = 1; value <= 13; value++) {
    cards.push({ suit, value })
  }
}
// value가 2인 카드
cards.filter(c => c.value === 2) // [{suit: "H", value: 2},{suit: "C", value: 2},{suit: "D", value: 2},{suit: "S", value: 2}]

// 다이아몬드
cards.filter(c => c.suit === 'D').length // 13
// 킹, 퀸, 주니어
cards.filter(c => c.value > 10).length // 12
// 하트의 킹, 큉, 주니어
cards.filter(c => c.value > 10 && c.suit === 'H').length // 3

reduce

map 이 배열의 각 요소를 변형한다면, reduce 는 배열 자체를 변형한다. reduce 의 첫 번째 매개변수는 배열이 줄어드는 대상이고, 두 번째 매개변수 부터는 현재 배열요소, 현재 인덱스, 배열 자체이다.

const arr = [5, 7, 2, 4]
const sum = arr.reduce((a, x) => (a += x), 0) // 18

위 코드에서 reduce 의 콜백 함수는 매개변수로 누적값 a 와 현재 배열 요소 x 를 받았습니다. 코드에서의 누적값은 0 부터 시작합니다.

  1. 첫 번째 배열 요소 5 에서 함수를 호출한다. a 의 초깃값은 0 이고 x 의 값은 5 이다. 함수는 a 와 x(5)의 합을 반환한다. 이 값은 다음 단계의 a 의 값이 된다.
  2. 두 번째 배열 요소 7 에서 함수를 호출한다. a 의 초깃값은 이전 단계에서 전달한 5 이고, x 의 값은 7 이다. 함수는 a 와 x 의 합 12 를 반환한다. 이 값은 다음 단계의 a 의 값이 된다.
  3. 세 번째 배열 요소 2 에서 함수를 호출한다. 이 단계에서 a 는 12 이고 x 는 2 이다. 함수는 a 와 x 의 합인 14 를 반환한다.
  4. 마지막 배열 요소인 4 에서 함수를 호출한다. a 는 14 이고 x 는 4 이다. 함수는 a 와 x 의 합인 18 을 반환하며 이 값은 reduce 의 값이고 sum 의 값이 된다.

삭제되거나 정의되지 않은 요소들

WARNING

map, filter, reduce 는 삭제되거나 정의되지 않은 요소들에서 콜백 함수를 호출하지 않는다.

const arr = [1, 2, 3, 4, 5]
delete arr[2]
arr.map(x => 0) // [0, 0, undefined, 0, 0]

문자열 병합

join 매서드는 매개변수로 구분자 하나를 받고 요소들을 하나로 합친 문자열을 반환한다. 이 매개변수가 생략되었을 경우, 기본값은 쉼표이며, 정의되지 않은 요소, 삭제된 요소, null, undefined 는 모두 빈 문자열로 취급된다.

const arr = [1, null, 'hello', 'world', true, undefined]
delete arr[3]
arr.join() // "1,,hello,,true,"
arr.join('') // "1hellotrue"
arr.join(' -- ') // "1 --  -- hello --  -- true -- "

요약

배열 콘텐츠 조작

하고 싶은 일사용할 매서드수정 또는 사본
스택(후입 선출)을 만들때push(바뀔 길이 반환), pop배열 수정
큐(선입 선출)를 만들때unshift(바뀔 길이 반환), shift배열 수정
여러 요소를 배열 마지막에 추가할 때concat사본 반환
배열 일부가 필요할 때slice사본 반환
임의의 위치에 요소를 추가하거나 제거할 때splice배열 수정
배열 안에서 요소를 교체할 때coptWithin배열 수정
배열을 채울 때fill배열 수정
배열을 반대로 정렬할 때reverse배열 수정
배열을 정렬할 때sort배열 수정

배열 검색

찾고자 하는 것사용할 매서드
요소의 인덱스indexOf, findIndex
인덱스를 뒤에서부터 찾을 때lastIndexOf
요소 자체find
조건을 만족하는 요소가 들어있는지 확인할 때some
모든 요소가 그 조건을 만족하는지 확인할 때every

배열 변형

하고 싶은 일사용할 매서드수정 또는 사본
배열의 모든 요소를 변형할 때map사본 반환
조건에 맞는 요소만 남길 때filter사본 반환
배열 전체를 다른 데이터 타입으로 변형할 때reduce사본 반환
요소를 문자열로 바꿔서 하나로 합칠 때join사본 반환