프론트엔드/Javascript

자바스크립트 배열 다루기

.log('FE') 2021. 12. 9. 23:19
728x90
반응형

자바스크립트에서 배열을 다룰때 주의해야할 몇가지 내용들이 있습니다. 그 중에 가장 중요하다 생각하는건 Immutability (불변성) 입니다. 즉 원본 배열을 수정하느냐 아니면 새로운 배열을 만들어 내느냐에 대한 기본적인 이해를 바탕으로 사용해야 사이드 이펙트를 피할 수 있습니다.

 

원본 배열을 수정

Array.prototype.push <=> Array.prototype.pop

대표적인 배열 원본을 수정하는 메소드입니다.  push 는 배열의 가장 마지막에 값을 추가하고 pop 은 가장 마지막의 값을 추출합니다.

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

arr.push(10) // [1, 2, 3, 4, 5, 10]
arr.pop() // [1, 2, 3, 4, 5]

 

Array.prototype.shift <=> Array.prototype.unshift

push 와 pop 과 반대되는 개념으로 배열의 가장 첫번째에 값을 추가하거나 제거할 수 있습니다.

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

arr.unshift(10) // [10, 1, 2, 3, 4, 5]
arr.shift() // [1, 2, 3, 4, 5]

 

Array.prototype.splice

splice 는 기존 배열에 요소를 삭제, 교체, 추가를 하는것이 가능합니다. 위에 작성된 메소드들과 다르게 원하는 index 를 지정할 수 있습니다.

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

arr.splice(0, 1) // [2, 3, 4, 5] - 0 번째 index 부터 1개의 요소를 추출
arr.splice(0, 1, 10) // [10, 3, 4, 5] - 0번째 index 부터 1개의 요소를 3번째 매개변수 값으로 교체
arr.splice(2, 0, 20) // [10, 3, 20, 4, 5] - 2번째 index 에 세번째 매개변수를 추가

 

Array.prototype.sort <=> Array.prototype.reverse

sortreverse 는 원본 배열을 정렬주는 메소드입니다.

const arr = [10, 20, 1, 2, 3]

arr.sort() // [1, 10, 2, 20, 3]
arr.reverse() // [3, 20, 2, 10, 1]

정렬 메소드인데 뭔가 이상한걸 볼 수 있습니다. 분명 1 다음엔 2가 와야할것같지만 10이 오고 있습니다. 숫자의 비교가 아닌 문자비교를 하기때문에 앞자리가 같은 10이 1다음 20이 2 다음으로 오고있습니다. 정상적으로 숫자의 정렬을 위해서는 대소를 비교하여 정렬되도록 해야합니다.

arr.sort((a, b) => a - b) // [1, 2, 3, 10, 20]

 

 

원본 배열 불변성 유지

Array.prototype.map

map 메소드는 원본 배열을 순회하면서 콜백함수를 실행하고 새로운 배열을 반환하는 메소드입니다. 따라서 원본 배열의 불변성을 유지 할 수 있습니다.

const users = [
  { firstName: '홍', lastName: '길동', age: 12 },
  { firstName: '강', lastName: '호동',  age: 30 },
  { firstName: '해리', lastName: '포터', age: 100 },
  { firstName: '나무', lastName: '늘보', age: 12 },
]

const userFullName = users.map(user => `${user.firstName}${user.lastName}`)

console.log(userFullName) // [ '홍길동', '강호동', '해리포터', '나무늘보' ]
console.log(users) // 원본 변화 없음

 

VanilsJSSPA 를 구현하려고 하다보면 돔을 조작하는 api 를 많이 사용하게 되는데 이때 map 메소드가 자주 사용됩니다. 그러나 map 은 배열의 메소드로 유사배열로 취급되는  NodeList 는 배열 메소드를 사용할 수 없습니다. 그래서 배열로 취급될 수 있도록 변환하는 작업이 필요합니다.

 

// Array.from()
const lis = document.querySelectorAll('li');
const liArr = Array.from(lis, x => x);

Object.prototype.toString.call(lis) // [object NodeList]
Object.prototype.toString.call(liArr) // [object Array]

그래서 NodeList 객체의 프로토타입을 확인해보면 

  1. entries: ƒ entries()
  2. forEach: ƒ forEach()
  3. item: ƒ item()
  4. keys: ƒ keys()
  5. length: (...)
  6. values: ƒ values()

사용가능한 프로퍼티는 이정도로 확인할 수 있습니다.

 

유사배열객체를 배열로 전환하는 방법에는 더 쉬운 방법이 있습니다. 전개 구문 을 활용하면 더 쉽게 배열로 만들어 사용할 수 있습니다.

const liArr = [...lis]

 

 

Array.prototype.filter

filter 메소드는 배열객체에서 원하는 항목만 추출하여 새로운 배열로 만들어 활용할 수 있습니다.

const users = [
  { firstName: '홍', lastName: '길동', age: 12 },
  { firstName: '강', lastName: '호동',  age: 30 },
  { firstName: '해리', lastName: '포터', age: 100 },
  { firstName: '나무', lastName: '늘보', age: 12 },
]

const filterUsers = users.filter(user => user.age === 12)
console.log(filterUsers)
//
[
   { firstName: '홍', lastName: '길동', age: 12 },
   { firstName: '나무', lastName: '늘보', age: 12 } 
]

 

 

Array.prototype.flat and reduce and concat

flat, reduce, concat 은 서로 닮아 있는 부분들이 있어서 하나의 예제에서 진행하려고 합니다.

const arr = [ 1, 2, [ 3, 4 ] ];
const arr1 = [ 1, 2, [ 3, 4, [ 5, 6 ] ] ];
consr arr2 = [1, 2,  , 4, 5]

arr.flat() // [1, 2, 3, 4]
arr1.flat() // [1, 2, 3, 4, [5, 6]]
arr1.flat(2) // [1, 2, 3, 4, 5, 6] - 2뎁스까지 하나의 배열로 병합
arr2.flat() // [1, 2, 4, 5] -  배열에 빈 공간 제거

flat 은 중첩 배열을 하나의 배열로 만들거나 배열내의 빈 공간을 제거할 수 있습니다. 이 모든것이 원본 배열은 수정하지않고 새로운 배열로 생성합니다.

 

const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]
const arr3 = [1, 2, 3, [4, 5]]

arr1.concat(arr2) // [1, 2, 3, 4, 5, 6]
arr1.concat(1, [2, 3]) // [1, 2, 3, 1, 2, 3]
[].concat(...arr3) // [1, 2, 3, 4, 5]

concat 은 서로 다른 배열 객체간에 병합하여 하나의 배열을 만들어 활용할 수 있습니다. 이러한 특성을 활용하여 flat 메소드와 동일한 동작을 하도록 활용할 수도 있습니다.

 

const arr = [1, 2, 3, 4, 5]
arr.reduce((a, b) => a + b) // 15

리듀스는 다른 메소드들과 다르게 이해하기 어렵다 라고 생각되는 부분들이 있습니다. 바로 누적이라는 개념때문인데요. 콜백함수로 넘어오는 매개변수들을 하나하나 풀어서 보고 이해하면 그리 어렵지 않게 이해할 수 있습니다.

 

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

function callback (accumulator, currentValue, currentIndex, array) {
  return accumulator + currentValue
}
arr.reduce(calback)

 

위 예제는 처음 작성했던것과 완전히 동일한 예제입니다. 매개변수를 하나씩 확인해보면

accumulator : 누적되어지는 매개변수입니다.

currentValue: 배열의 값들을 순차적으로 받는 매개변수입니다.

currentIndex: 현재 순회중인 배열의 인덱스값입니다.

array: 원본 배열입니다.

 

여기서 세번째와 네번째 매개변수값은 보통 사용하지 않고 누적매개변수와 순회중인 매개변수 두가지만 활용합니다. 그렇게 사용한것이 첫번째 예제입니다. currentValue 로 순차적으로 값을 받아와 그 값은 accumulator 에 계속 누적합산됩니다.

 

728x90
반응형