[2020 최신 ES6+] 자바스크립트 배열 기본부터 응용까지 완벽 정리

남양주개발자

·

2016. 10. 15. 16:32

728x90
반응형

자바스크립트로 개발을 하다 보면 배열이라는 자료구조를 접하게 됩니다. 배열이란 무엇일까요? 그리고 배열은 어떤 경우에 사용이 되고 어떤 기능을 가지고 있을까요? 이번 포스팅에서는 배열을 다루기 위한 모든 것을 설명하려고 합니다.

배열이란?

배열은 모든 언어(파이썬(Python), 자바(Java), C, 자바스크립트(Javascript))에서 지원하고 있는 자료구조입니다. 배열을 간단히 설명드리면 연관된 데이터를 하나의 틀에서 관리하기 위한 자료구조입니다. 변수가 하나의 데이터를 저장하기 위한 것이라면 배열은 여러 개의 데이터를 하나의 변수에 저장하기 위한 것이라고 할 수 있습니다.

사용하는 언어에 따라서 배열의 특성이 조금 다를 수 있지만, 기본적인 동작 원리는 동일하기 때문에 다른 언어를 사용하시더라도 이해하시기 크게 무리가 없습니다. 

예를 들어, 자바는 배열을 선언할 때 배열의 데이터 타입까지 지정합니다. 만약 int 타입의 배열이 선언되면 배열 안에 int 타입의 값만 담을 수 있습니다. 하지만 자바스크립트는 타입이 고정되어 있지 않으므로, 같은 배열에 있는 배열 요소끼리의 타입이 서로 다를 수도 있습니다.
const val = 'hello'; // hello 문자열을 가진 var 변수
const arr = ['hello', 1, null]; // hello, 1 그리고 null 값을 가지고 있는 배열 arr 변수

배열은 언제 사용될까?

배열은 여러 개의 데이터를 하나의 변수에 저장하기 위해 사용된다고 설명드렸습니다. 그럼 왜 여러 개의 데이터를 하나의 변수에 저장해야 될까요? 

10명의 학생 이름을 저장하는 프로그램을 만든다고 가정해봅시다.

만약 배열을 사용하지 않고 10명의 학생을 저장한다고 하면 아래의 예시와 같이 각 학생들의 이름을 저장하기 위한 변수를 정의해야 합니다.

// 학생을 저장하기 위해 10개의 변수를 생성
const student1 = '학생1';
const student2 = '학생2';
const student3 = '학생3';
const student4 = '학생4';
const student5 = '학생5';
const student6 = '학생6';
const student7 = '학생7';
const student8 = '학생8';
const student9 = '학생9';
const student10 = '학생10';

굉장히 비효율적입니다! 10명의 학생 이름을 저장해서 아직은 작성할 만 하지만, 만약 100명의 학생이라면? 1만 명의 학생을 저장해야 된다면? 생각만 해도 굉장히 끔찍합니다. 그러면 좀 더 효율적으로 학생 이름을 저장하려면 어떤 방식을 사용해야 할까요? 바로 배열을 활용하는 것입니다.

// 학생들의 이름을 가지고 있는 배열 students
const students = [
  '학생1',
  '학생2',
  '학생3',
  '학생4',
  '학생5',
  '학생6',
  '학생7',
  '학생8',
  '학생9',
  '학생10'
]

모든 학생들의 목록을 저장한 배열을 students라는 변수 이름으로 정의했습니다. 저희가 정의한 변수가 10개에서 1개로 줄었습니다. 제가 효율적이라고 표현했던 부분이 과연 여기서 끝일까요? 아닙니다! 배열의 마법은 여기서 끝이 아닙니다. 배열을 사용하면 배열에서 가지고 있는 다양한 기능들(built-in method)을 사용할 수 있습니다.

배열 생성 방법

자바스크립트에서 배열을 만들기 위해서는 대괄호([])를 사용하는데 대괄호는 배열을 만드는 기호입니다. 대괄호 안에 데이터를 콤마(,)로 구분해서 나열하면 배열이 됩니다. 자바스크립트에서 배열을 만드는 방식에는 2가지가 있습니다.

  • 배열 리터럴 대괄호([ ])를 사용하여 만드는 방법
  • Array() 생성자 함수로 배열을 생성하는 방법

배열 리터럴 대괄호([ ])를 사용하여 만드는 방법

자바스크립트에서 배열 리터럴을 활용하여 배열을 만들 수 있습니다.

const arr = []; // 배열 생성 (빈 배열)
const arr1 = [1,2,3,4]; // 배열 생성 (숫자를 포함한 배열)
const arr2 = ['h', 'e', 'l', 'l', 'o']; // 배열 생성 (문자를 포함한 배열)
const nums = [1,2,3,4];

Array() 생성자 함수로 배열을 생성하는 방법

배열을 생성하는 방법에는 배열 리터럴을 사용하는 방식 외에 Array() 생성자 함수로 배열을 생성하는 방법도 있습니다. 하지만, 코드 가독성이나 사이드 이펙트 문제가 발생할 수 있는 방식임으로 안티 패턴으로 분류되니 참고 바랍니다.

// 배열 생성
const arr = new Array();

// 배열 생성(초기 값 할당)
const arr1 = new Array('h', 'e', 'l', 'l', 'o'); 

// 배열 생성 (배열 크기 지정)
const arr2 = new Array(3);

이렇게 생성자 함수로 배열을 생성할 수 있고 생성하는 방법은 두 방법 거의 동일한 것을 알 수 있습니다.

하지만 배열 리터럴을 사용하는 것이 훨씬 코드가 간결하고 직관적이며 속도 면에서도 좋습니다. 실제로 자바스크립트 엔진은 리터럴 표기법에 맞게 최적화되어있습니다. 배열 생성자 함수를 사용할 때 숫자 한 개를 파라미터로 넘기면 숫자에 해당하는 길이의 배열을 생성하게 됩니다. API 스펙과 기대하는 동작이 다소 혼동될 수 있으니 주의해야 합니다. 이러한 이슈가 있기 때문에 생성자 함수로 배열을 생성하기보다는 배열 리터럴 방식으로 배열을 생성하는 것을 권장드립니다.

배열의 특징

특정 요소에 접근하는 방법

배열을 만들기 위해서는 대괄호([])를 사용하고 대괄호 안에 요소(element)를 콤마(,)로 나눈다고 말씀드렸습니다. 이렇게 콤마로 나눠진 요소들은 배열 안에서 고유한 인덱스(index) 값을 가지게 됩니다.

인덱스란 배열에 저장한 요소에 쉽게 접근하기 위해서 사용되는 값입니다.

const arr = ['h', 'e', 'l', 'l', 'o'];
// arr[0] === 'h'
// arr[3] === 'l'

이처럼 인덱스는 0번째부터 시작하고, 우리가 지정한 배열 변수에 인덱스를 붙이면 지정된 인덱스의 요소를 접근할 수 있습니다. 필요에 따라서 다른 변수에 인덱스로 접근한 값을 할당할 수도 있습니다.

const arr = ['h', 'e', 'l', 'l', 'o'];

const first = arr[0]; // h
const last = arr[arr.length - 1]; // o

배열의 길이를 얻는 방법

배열의 길이를 얻기 위해서는 배열의 내장 프로퍼티를 활용하면 쉽게 얻을 수 있습니다.

const arr = ['h', 'e', 'l', 'l', 'o'];
// arr.length -> 6

조금 더 응용해 볼까요?

만약 배열의 마지막 요소에 접근하고 싶다면 어떻게 하면 될까요?

배열의 인덱스는 0부터 시작한다는 점 말씀드렸습니다. 만약 5개의 요소를 가지고 있는 배열이라면 마지막 요소의 인덱스는 4겠죠? 그러면 아래와 같이 작성하면 쉽게 마지막 요소에 접근할 수 있습니다.

const arr = ['h', 'e', 'l', 'l', 'o'];
// arr[arr.length - 1] -> 'o'
// 배열의 길이 (arr.length)는 5
// 마지막 요소의 인덱스는 4

배열에 요소를 추가, 수정, 삭제하는 방법

배열은 복수의 데이터를 효율적으로 관리, 전달하기 위한 목적으로 고안된 데이터 타입입니다. 따라서 데이터의 추가/수정/삭제와 같은 일을 편리하게 할 수 있도록 돕는 다양한 내장 기능을 가지고 있습니다.

요소를 추가하는 방법

배열에 요소를 추가할 때는 push 메서드와 unshift 메서드를 활용하면 됩니다. 배열의 앞쪽에 요소를 추가할 때는 unshift를 사용하고, 배열의 끝쪽(맨 뒤)에 요소를 추가할 때는 push 메서드를 사용합니다.

// 배열의 앞쪽에 요소를 추가할 때
const arr = ['h', 'e', 'l', 'l', 'o'];
arr.unshift('f');
// arr -> ['f', 'h', 'e', 'l', 'l', 'o']
// arr.length -> 6
// 배열의 뒤쪽에 요소를 추가할 때
const arr = ['h', 'e', 'l', 'l', 'o'];
arr.push('f');
// arr -> ['h', 'e', 'l', 'l', 'o', 'f']
// arr.length -> 6

요소를 삭제하는 방법

배열에 요소를 삭제할 때는 pop 메서드와 shift 메서드를 활용하면 됩니다. 배열의 앞쪽에 요소를 삭제할 때는 shift를 사용하고, 배열의 끝쪽(맨 뒤)에 요소를 삭제할 때는 pop 메서드를 사용합니다. pop 메서드와 shift 메서드는 제거한 요소를 반환하는 특징이 있습니다.

// 배열의 뒤쪽에 있는 요소를 삭제할 때
const arr = ['h', 'e', 'l', 'l', 'o'];
arr.pop(); // 'o'
// arr -> ['h', 'e', 'l', 'l']
// arr.length -> 4
// 배열의 앞쪽에 있는 요소를 삭제할 때
const arr = ['h', 'e', 'l', 'l', 'o'];
arr.shift(); // 'h'
// arr -> ['e', 'l', 'l', 'o']
// arr.length -> 4

특정 요소 삭제하는 방법

배열에 앞쪽과 뒤쪽에 요소를 삭제하는 방법도 있지만 특정 인덱스의 요소를 삭제하고 싶을 때가 있습니다. 특정 요소를 삭제할 때는 배열의 splice 메서드를 사용합니다. splice 메서드는 삭제한 값들을 반환하는 특징을 가지고 있습니다.

splice메서드의 매개변수는 start와 deleteCount로 구성되어 있습니다.

start는 배열의 변경을 시작할 인덱스입니다. 배열의 길이보다 큰 값이라면 실제 시작 인덱스는 배열의 길이로 설정됩니다. 음수인 경우 배열의 끝에서부터 요소를 세어나갑니다(원점 -1, 즉 -n이면 요소 끝의 n번째 요소를 가리키며 array.length - n번째 인덱스와 같음). 값의 절댓값이 배열의 길이보다 큰 경우 0으로 설정됩니다.

deleteCount는 배열에서 제거할 요소의 수입니다. deleteCount를 생략하거나 값이 array.length - start보다 크면 start부터의 모든 요소를 제거합니다. deleteCount가 0 이하라면 어떤 요소도 제거하지 않습니다. 이 때는 최소한 하나의 새로운 요소를 지정해야 합니다.

이해가 안 간다면 우선 특정 요소를 삭제하는 방법은 splice(삭제할 인덱스 번호, 1)을 사용하면 된다라고만 기억하시면 됩니다.

// 배열의 앞쪽에 있는 요소를 삭제할 때
const arr = ['h', 'e', 'l', 'l', 'o'];
arr.splice(1, 1); // ['e']
// arr -> ['h', 'l', 'l', 'o']
// arr.length -> 4

자주 사용하는 메서드

배열에는 위에서 소개한 기본적인 기능들을 포함해서 정말 유용한 기능들을 많이 가지고 있습니다. 개발하면서 자주 사용할 수 있는 메서드들을 소개하겠습니다.

값으로 인덱스를 찾는 방법 (indexOf)

값으로 인덱스를 찾는 방법도 있습니다. 배열의 indexOf 메서드를 활용하면 값으로 인덱스를 찾을 수 있습니다. 배열에서 주어진 값과 일치하는 제일 앞의 인덱스를 반환합니다. 없으면 -1을 반환합니다.

const arr = ['h', 'e', 'l', 'l', 'o'];
arr.indexOf('e'); // 1

배열끼리 합치는 방법 (concat)

배열을 매개변수로 주어진 배열/값과 이어 붙인 새로운 배열을 반환합니다.

// 두 배열을 합치는 방법
const arr1 = ['h', 'e'];
const arr2 = ['l', 'l', 'o'];
const newArr = arr1.concat(arr2); // ['h', 'e', 'l', 'l', 'o']

// 여러 개 합치는 방법
const num1 = [1, 2, 3];
const num2 = [4, 5, 6];
const num3 = [7, 8, 9];

num1.concat(num2, num3);
// 결과: [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 배열에 값을 합치는 방법
const alpha = ['a', 'b', 'c'];

alpha.concat(1, [2, 3]);
// 결과: ['a', 'b', 'c', 1, 2, 3]

배열을 반전시키는 방법 (거꾸로 돌리는 방법) (reverse)

배열의 reverse 메서드를 활용해서 기존 배열을 거꾸로 돌릴 수 있습니다.

const a = [1, 2, 3];
console.log(a); // [1, 2, 3]

a.reverse();
console.log(a); // [3, 2, 1]

배열을 정렬시키는 방법 (sort)

배열은 기본적으로 정렬하는 sort 메서드를 가지고 있습니다.

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
// 결과 ["Dec", "Feb", "Jan", "March"]

하지만 숫자를 정렬할 경우 조금 의도한 바와는 다른 결과를 받게 됩니다.

const array1 = [1, 30, 4, 21, 100000];
array1.sort();
// 결과 [1, 100000, 21, 30, 4]

그 이유는 sort 메서드의 매개변수인 compareFunction 값을 생략하게 된다면 배열은 각 요소의 문자열 변환에 따라 각 문자의 유니 코드 코드 포인트 값에 따라 정렬됩니다. 예를 들어 "바나나"는 "체리"앞에 오게 되지만, 숫자 정렬에서는 9가 80보다 앞에 오지만 숫자는 문자열로 변환되기 때문에 "80"은 유니 코드 순서에서 "9" 앞에 오게 됩니다. 숫자를 제대로 정렬하려면 sort 메서드의 매개변수를 적절하게 잘 활용하면 됩니다.
문자열 대신 숫자를 비교하기 위해 compareFunction는 a에서 b를 뺄 수 있습니다. 다음 함수는 배열을 오름차순으로 정렬합니다

const numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return a - b;
});
// [1, 2, 3, 4, 5]

내림차순 정렬을 하려면 a - b를 b - a로만 바꿔주면 됩니다.

const numbers = [4, 2, 5, 1, 3];
numbers.sort(function(a, b) {
  return b - a;
});
// [5, 4, 3, 2, 1]

배열의 모든 요소를 문자열로 합치는 방법 (join)

배열의 모든 요소를 문자열로 합칠 때는 join 메서드를 활용하면 됩니다. join 매개변수에 아무것도 전달하지 않을 경우 기본값으로 콤마(,)를 기준으로 배열의 요소를 합칩니다. 매개변수가 존재할 경우 매개변수의 값을 기준으로 배열의 요소를 합치게 됩니다.

const a = ['바람', '비', '불'];
const val1 = a.join();      // myVar1에 '바람,비,불'을 대입
const val2 = a.join(', ');  // myVar2에 '바람, 비, 불'을 대입
const val3 = a.join(' + '); // myVar3에 '바람 + 비 + 불'을 대입
const val4 = a.join('');    // myVar4에 '바람비불'을 대입

고급

여기에서 소개하는 메서드들은 실제 업무에서도 많이 활용되고 자주 사용됩니다.

map 메서드

배열의 모든 요소 각각에 대하여 주어진 콜백 함수를 호출하고, 배열의 각 요소에 대해 실행한 callback의 결과를 모은 새로운 배열을 반환합니다. map 메서드의 구문은 아래와 같습니다.

// currentValue 처리할 현재 요소
// index 처리할 현재 요소의 인덱스
// array map()을 호출한 배열
arr.map(callback(currentValue[, index[, array]])[, thisArg])
const arr = ['first', 'second', 'third'];
 
arr.map((currentValue, index, array) => {
  console.log(currentValue); 
})
// first
// second
// third

 

실전 예제

아래 코드는 items의 데이터 중에 price값을 콤마 처리해서 새로운 배열인 newItems를 생성합니다.

// example
const items = [
  {
    id: 1,
    name: '맥북',
    price: 2930000
  },
  {
    id: 2,
    name: '아이패드',
    price: 800000
  },
  {
    id: 3,
    name: '아이폰',
    price: 450000
  },  
];

const newItems = items.map(item => {
  return {
    ...item,
    price: item.price.toLocaleString()
  }
})

console.log(newItems);

filter 메서드

업무 중에 굉장히 자주 사용되는 메서드 중 하나입니다. 배열의 특정 값을 기준으로 필터링할 때 사용합니다.

// element 처리할 현재 요소
// index 처리할 현재 요소의 인덱스
// array filter()을 호출한 배열
arr.filter(callback(element[, index[, array]])[, thisArg])

 

실전 예제

아래 코드는 items의 데이터 중에 count값이 1 이상인 값들만 새로운 배열의 요소로 추가합니다.

// example
const items = [
  {
    id: 1,
    name: '맥북',
    price: 2930000,
    count: 5
  },
  {
    id: 2,
    name: '아이패드',
    price: 800000,
    count: 2
  },
  {
    id: 3,
    name: '아이폰',
    price: 450000,
    count: 0
  },  
];

const newItems = items.filter(item => {
  return item.count > 0
})

console.log(newItems);

reduce 메서드

map과 filter 메서드와 같이 굉장히 많이 사용됩니다. 순회하면서 값을 축적시킬 때 많이 사용합니다. reduce 메서드의 콜백함수는 4개의 매개변수를 가집니다. 축적값(accumulator, acc), 현재 값(curr), 현재 인덱스(index), 원본 배열 (arr)

reduce 메서드의 반환 값은 축적값(acc)에 할당되고, 축적값(acc)는 순회 중 유지되므로 결국 최종 결과는 하나의 값이 됩니다. reduce 메서드의 2번째 매개변수는 초기값을 설정할 수 있는 initialValue을 가집니다. 되도록 초기값은 설정하도록 합니다.

실전 예제

해당 코드는 items의 가격을 모두 합한 값을 sumPrice 변수의 초기값으로 설정하는 예시입니다.

// example
const items = [
  {
    id: 1,
    name: '맥북',
    price: 2930000
  },
  {
    id: 2,
    name: '아이패드',
    price: 800000
  },
  {
    id: 3,
    name: '아이폰',
    price: 450000
  },  
];

const sumPrice = items.reduce((acc, curr) => {
   return acc + curr.price
}, 0)

console.log(sumPrice) // 4180000

 

728x90
반응형
그리드형

💖 저자에게 암호화폐로 후원하기 💖

아이콘을 클릭하면 지갑 주소가자동으로 복사됩니다