배열이란...?

배열은 여러 개의 값을 순차적으로 나열한 자료구조이다. 사용빈도가 매우 높고 가장 기본적인 자료구조다. JS에서는 배열을 다루기 위한 여러 유용한 메서드를 제공한다.

const arr = ["apple", "banana", "orange"];
// 인덱스 값 
arr[0] // apple
arr[1] // banana
arr[2] // orange
arr.length // 3
  • 배열이 가지고 있는 값을 요소라 한다.
  • 원시값, 객체, 함수, 배열 등 자바스크립트에서 값으로 인정하는 모든 것은 배열의 요소가 될 수 있다.
  • 배열의 요소는 배열에서 자신의 위치를 나타내는 0이상의 정수인 인덱스를 갖는다.(0부터 시작한다)
  • 배열의 길이를 나타내는 length 프로퍼티를 갖는다.
  • 자바스크립트에서의 배열이라는 타입은 존재하지 않으며 배열은 객체 타입이다.
typeof arr // object

배열 생성방법
1. 배열 리터럴
2. Array 생성자 함수
3. Array.of 메서드
4. Array.from 메서드

const arr = [1, 2, 3];

arr.constructor === Array // true 배열의 생성자 함수는 Array이다.
Object.getPrototypeOf(arr) === Array.prototype // true 배열의 프로토타입 객체는 Array.prototype이다. 
// 즉, arr의 프로토타입은 Array.prototype

배열은 객체지만 일반 객체와는 구별되는 독특한 특징이 있다.

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

표를 보면 즉, 배열은 값의 순서(인덱스로 표현되는)가 있고 ! length프로퍼티를 갖는다. 즉 배열의 장점은 순서가 있기에 순차적, 역순이나 특정위치로부터 요소에 접근할 수 있다.

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

자료구조에서 말하는 배열은 밀집 배열이다.

밀집 배열 (dense array)
배열의 요소가 하나의 데이터 타입으로 통일되어있으며 연속적으로 인접해있다
그러므로
1. 인덱스를 통해 단 한번의 연산으로 특정 요소에 접근이 가능하다. (O(1))
2. 정렬되지 않은 배열의 경우 처음 위치부터 선형적으로 검색해야 한다. (O(n))

// 선형 검색을 통해 배열(array)에 특정 요소(target)가 존재하는지 확인한다.
// 배열에 특정 요소가 존재하면 특정 요소의 인덱스를 반환하고, 존재하지 않으면 -1을 반환한다.
function linearSearch(array, target) {
  const length = array.length;

  for (let i = 0; i < length; i++) {
    if (array[i] === target) return i;
  }

  return -1;
}

console.log(linearSearch([1, 2, 3, 4, 5, 6], 3)); // 2
console.log(linearSearch([1, 2, 3, 4, 5, 6], 0)); // -1

자바스크립트에서의 배열은 희소 배열이다.

배열 요소 각각의 메모리 공간은 동일한 크기를 갖이 않아도 되며 연속적으로 이어져 있지 않을 수 있다.

즉, 자바스크립트의 배열은 일반적인 배열을 흉내 낸 특수한 객체다.

// 배열의 고유한 속성 설명자
console.log(Object.getOwnPropertyDescriptors([1, 2, 3]));
/*
{
  '0': {value: 1, writable: true, enumerable: true, configurable: true}
  '1': {value: 2, writable: true, enumerable: true, configurable: true}
  '2': {value: 3, writable: true, enumerable: true, configurable: true}
  length: {value: 3, writable: true, enumerable: false, configurable: false}
}
*/

엄밀히 말하면 자바스크립트 배열은 해시 테이블로 구현된 객체이다.
인덱스로 요소에 접근하는 경우 일반적인 배열보다 성능적인 면에서 느릴수 밖에 없는 구조적인 단점이 있다. 하지만 요소를 삽입 또는 삭제하는 경우에는 일반적인 배열보다 빠른 성능을 기대할 수 있다.
그리하여 모던 자바스크립트 엔진은 배열을 일반 객체와 구별하여 좀 더 배열처럼 동작하도록 최적화하여 구현하여서 일반객체보다 약 2배정도 빠르다.

length 프로퍼티와 희소배열

배열의 길이를 나타내는 0 이상의 정수 값을 가진다. (빈 배열이면 "0")

[].length // 0
[1, 2, 3] // 3
  • length 프로퍼티의 값은 배열에 요소를 추가하거나 삭제하면 자동 갱신된다.
  • length는 배열의 길이를 바탕으로 결정되지만 임의의 숫자 값을 명시적으로 할당 가능하다.
    • 현재 길이보다 더 작은 값을 length 프로퍼티에 할당하면 길이가 줄어든다.
const arr = [1, 2, 3, 4, 5];


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

// 배열의 길이가 5에서 3으로 줄어든다.
console.log(arr); // [1, 2, 3]
  • 희소배열은 length와 배열의 요소 개수가 일치하지 않으면, length가 항상 더 크다.
const arr = [1, 2, 3]
// 현재 length 프로퍼티 값인 3보다 큰 값 5를 length 프로퍼티에 할당
arr.length = 5;

// length 프로퍼티 값은 변경되지만 실제로 배열의 길이가 늘어나지 않는다
console.log(arr.length); // 5
console.log(arr); // [1, 2, 3, empty * 2];

const bin = [1 , , 3] // 희소 배열
console.log(bin) // [1, enpty, 3]

배열 생성

위에서 설명했듯이 배열 생성 방법은 4가지가 있다.

1. 배열 리터럴

배열리터럴 [] 사용한다. 가장 일반적이고 간편한 배열 생성 방식.

2. Array 생성자 함수

Array 생성자함수로 배열을 생성하면 생성된 배열은 희소 배열이다.

const arr = new Array(10);

console.log(arr); // [empty × 10]
console.log(arr.length); // 10

3. Array.of 메서드

Array 배열과 다르게 전달된 인수를 요소로 갖는 배열을 생성한다.

Array.of(1); // [1]
Array.of(1, 2, 3); // [1, 2, 3]
Array.of("string"); // ['string']

4. Array.from 메서드

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

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

//  length 만 존재하는 유사배열
Array.from({ length: 3 }); // [undefined, undefined, undefined]

// 이터러블을 변환하여 배열을 생성한다. 문자열은 이터러블이다.
Array.from('Hello'); // -> ['H', 'e', 'l', 'l', 'o']

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

배열 요소의 참조

배열의 요소에 참조 할때는 대괄호에 인덱스를 넣어 배열의 요소를 참조한다.

const arr = [1, 2];
console.log(arr[0]); // 1
console.log(arr[1]); // 2
console.log(arr[2]); // 없는 요소에 접근하면 undefined
// 희소 배열 또한 undefined
const bin = [1, , 3];
console.log(bin[1]); // undefined

배열의 요소의 추가와 갱신

존재하지 않는 인덱스를 사용해 값을 할당하면 새로운 요소가 추가된다. 이때 length 프로터티 값은 자동 갱신된다.

const arr = [0];
arr[1] = 1;
console.log(arr); // [0, 1]
console.log(arr.length); // 2
// 요소값의 갱신도 가능하다.
arr[1] = 10;
console.log(arr); // [0, 10]

배열의 요소의 삭제

배열은 사실 객체이기에 배열의 특정 요소를 삭제할때 delete연산자를 사용할 수 있다. 이때 delete연산자는 객체의 프로퍼티를 삭제하기에 프로퍼티 키가 '1'인 프로퍼티를 삭제한다. 이때 배열은 희소 배열이되므로 delete 연산자 보단 splice메서드를 사용하자.

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

// length 프로퍼티에 영향을 주지 않는다. 즉, 희소 배열이 된다.
console.log(arr.length); // 3

배열의 특정 요소 삭제는 splice 사용 !

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

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

배열 메서드

Array.protototype.some

자신을 호출한 배열을 순회하면서 콜백 함수를 호출한다.
콜백 함수 반환값이 단 한 번이라도 참이면 true, 거짓이면 false를 반환한다.

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

// 배열의 요소 중에 0보다 작은 요소가 1개 이상 존재하는지 확인
[5, 10, 15].some(item => item < 0); // -> false

// 배열의 요소 중에 'banana'가 1개 이상 존재하는지 확인
['apple', 'banana', 'mango'].some(item => item === 'banana'); // -> true

// some 메서드를 호출한 배열이 빈 배열인 경우 언제나 false를 반환한다.
[].some(item => item > 3); // -> false

Array.prototype.every

자신을 호출한 배열을 순회하면서 콜백 함수를 호출한다.

콜백 함수 반환값이 모두 참이면 true, 거짓이면 false를 반환한다.

// 배열의 모든 요소가 3보다 큰지 확인
[5, 10, 15].every(item => item > 3); // -> true

// 배열의 모든 요소가 10보다 큰지 확인
[5, 10, 15].every(item => item > 10); // -> false

// every 메서드를 호출한 배열이 빈 배열인 경우 언제나 true를 반환한다.
[].every(item => item > 3); // -> true

Array.prototype.flatMap

ES10에서 도입된 flatMap 메서드는 map 메서드를 통해 생성된 새로운 배열을 평탄화한다.
즉, map 메서드와 flat 메서드를 순차적으로 실행한다.

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

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

// flatMap은 map을 통해 생성된 새로운 배열을 평탄화한다.
arr.flatMap(x => x.split(''));
// -> ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']

단, flapMap 메서드는 flat 메서드처럼 인수를 전달하여 평탄화 깊이 지정 못함
그래서 1단계만 평탄화할수있다.
그러므로 중첩 배열의 평탄화 깊이를 지정할때는 map, flat 메서드 따로 호출하자 !!

profile
꺾여도 하는 마음

0개의 댓글