# 2. 배열

다른 언어와 비교

배열은 가장 간단한 메모리 데이터 구조입니다. 기존 언어에서 구현했던 배열은 생성 시에 특정 범위의 메모리를 할당하고 연속적으로 데이터를 저장합니다.여기서 중요한 포인트는 연속성(continuous)인접성(contiguous)입니다. 메모리 시작 주소 + (찾고자 하는 인덱스 x 한 블록에 할당된 메모리 블록 개수)로 계산하면 배열은 이렇게 원하는 원소에 바로 접근할 수 있습니다.

거의 모든 언어에 내장된 타입이지만 자바스크립트는 독특한 면을 가지고 있습니다.서로 상이한 타입의 데이터도 한 배열에 넣을 수 있고, 실질적으로 다른 언어의 List와는 다른 특성이 있습니다. Hash Map이나 Dictionary(Object)로 구현되었고, 메모리를 미리 할당해놓지 않고 동적 할당하므로 연속적으로 원소가 저장되지 않습니다. Linked List와 같은 방식으로 말이죠. 따라서, 우리가 a[2]를 읽고 싶다면 무조건 1201부터 탐색해나가면서 a[2]를 찾아나가야 합니다.

👉🏻 다른 언어와 JS 배열의 차이

HashMap: Key와 value를 묶어 하나의 entry로 저장하여 Map을 구현합니다. hashing을 사용하기 때문에 많은 양의 데이터를 검색하는데 뛰어난 성능을 보입니다. 싱글스레드 언어에서 주로 사용하며, 멀티스레드의 경우 HashTable을 씁니다.

Hashing: 키(Key) 값을 해시 함수(Hash Function)에 대입시켜 나온 결과를 주소로 사용하여 값(Value)에 접근하는 방법입니다. 키(Key) 값을 값(Value)이 저장되는 주소 값으로 바꾸기 위한 수식입니다.

최근의 자바스크립트 엔진은 모든 요소가 동일한 타입을 가지고 있는 배열인 경우 연속적으로 메모리를 할당합니다. 그러나 이런 동일한 타입 배열에 다른 타입의 원소를 삽입하려고 할 때 컴파일러는 전체 배열의 구조를 해제하고 다시 예전의 배열처럼 비연속적인 메모리를 할당합니다.

또한, ES6 문법에서 typedArray가 추가되면서 ArrayBuffer를 사용할 수 있게 되었습니다. ArrayBuffer는 인접한 메모리 블록을 제공하고 우리가 마음대로 다룰 수 있게 해줍니다. 메모리를 직접 다루는 것은 매우 Low Level이고 너무 복잡하기 때문에 View라는 것을 통해서 ArrayBuffer를 다룰 수 있습니다.

var buffer = new ArrayBuffer(8);
var view   = new Int32Array(buffer);
view[0] = 100;

기존의 배열로 WebGL 사용에 있어서 바이너리 데이터를 효과적으로 처리할 수 없는 심각한 성능 문제에 당면하면서, 요청에 따라 해당 기능이 도입되었고, 다른 언어들과 유사하게 typedArray의 버퍼를 통하여 이를 제어할 수 있게 되었습니다.

👉🏻 TypedArray와 ArrayBuffer


성능 차이

일반 배열 - 추가 : 수행 시간 - 1207ms

var LIMIT = 10000000;
var arr = new Array(LIMIT);
arr.push({a: 22});
console.time("Array insertion time");
for (var i = 0; i < LIMIT; i++) {
  arr[i] = i;
}
console.timeEnd("Array insertion time");

일반 배열 - 읽기 : 수행 시간 - 196ms

var LIMIT = 10000000;
var arr = new Array(LIMIT);
arr.push({a: 22});
for (var i = 0; i < LIMIT; i++) {
  arr[i] = i;
}
var p;
console.time("Array read time");
for (var i = 0; i < LIMIT; i++) {
  //arr[i] = i;
  p = arr[i];
}
console.timeEnd("Array read time");

Typed Array - 읽기 : 수행 시간 - 27ms

var LIMIT = 10000000;
var buffer = new ArrayBuffer(LIMIT * 4);
var arr = new Int32Array(buffer);
console.time("ArrayBuffer insertion time");
for (var i = 0; i < LIMIT; i++) {
  arr[i] = i;
}
console.time("ArrayBuffer read time");
for (var i = 0; i < LIMIT; i++) {
  var p = arr[i];
}
console.timeEnd("ArrayBuffer read time");

배열의 생성과 초기화

간단하게 Array 오브젝트를 활용하여 인스턴스를 선언, 생성, 초기화 할 수 있으며, 인덱스를 통하여 접근 및 반복문 등의 활용이 가능합니다.

let daysOfWeek = new Array();   
let daysOfWeek = new Array(7);  
let daysOfWeek = new Array('일요일','월요일','화요일','수요일','목요일','금요일','토요일');   
let daysOfWeek = [];
let daysOfWeek = ['일요일','월요일','화요일','수요일','목요일','금요일','토요일'];

피보나치 수열 구성

원하는 수열의 길이만큼 피보나치 수열을 구하는 함수 작성

function getFibonacci (number) {
  let fibonacci = [];
  fibonacci[0] = 1;
  fibonacci[1] = 2;
  for(let i = 2; i < number; i++) {
    fibonacci[i] = fibonacci[i-1] + fibonacci[i-2];    
  }
  return fibonacci;
}

원소 추가와 삭제

자바스크립트 배열은 가변 객체입니다. 배열의 크기가 미리 정해지는 다른 언어들과는 다르게, 배열을 다시 만들지 않고 원소를 쉽게 추가할 수 있고 객체 크기는 동적으로 커집니다.


추가

마지막 위치에 배열의 원소를 추가

let numbers = [0,1,2,3,4,5,6,7,8];
numbers[numbers.length] = 9;
numbers.push(10);

앞부분에 배열의 원소를 추가

let numbers = [0,1,2,3,4,5,6,7,8];
for (let i = numbers.length; i >= 0; i--) {
  numbers[i] = numbers[i-1];
}
numbers[0] = -1;
numbers.unshift(-2);

하나씩 배열을 뒤로 이동시키고 가장 앞에 -1을 할당합니다. 또는 내장 메서드인 unshift를 활용하는 것도 가능합니다.

중간 부분에 배열의 원소를 추가

let numbers = [0,1,2,3,7,8];
numbers.splice(4,0,4,5,6);
console.log(numbers);
// [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]

삭제

마지막 위치에 배열의 원소를 삭제

let numbers = [0,1,2,3,4,5,6,7,8];
numbers.pop();

앞부분에 배열의 원소를 삭제

let numbers = [0,1,2,3,4,5,6,7,8];
for (let i = 0; i < numbers.length; i++) {
  numbers[i] = numbers[i+1];
}
console.log(numbers[8], numbers.length);   
// undefined, 9

let numbers = [0,1,2,3,4,5,6,7,8];
numbers.shift();
console.log(numbers[8], numbers.length);
// undefined, 8

잉여원소가 발생되고 반복문이 마지막으로 실행될 때 i+1은 존재하지 않는 위치를 참조하게 됩니다. 값을 덮어쓴 것이지 삭제가 아닙니다. shift() 메서드를 사용하여 길이도 줄이면서 원소를 삭제하는 것이 가능합니다.

중간 부분에 배열의 원소를 삭제

let numbers = [0,1,2,7,7,3,4,5];
numbers.splice(3,2);
console.log(numbers);
// [ 0, 1, 2, 3, 4, 5]

다차원 배열(Nested Array)

배열을 가진 배열로 행렬, 좌표값과 같은 2차원 데이터나 공간과 같은 3차원 이상의 데이터를 표현하기에 적합합니다. 행-우선(row-major)순위로 표현하면 다음과 같습니다.

let averageTemp = [
  [72,75,79,79,81],
  [81,79,75,75,73],
  [72,73,76,81,83]
];

// col 0  col 1  col 2  col 3  col 4
   [0][0] [0][1] [0][2] [0][3] [0][4] // row 0 
   [1][0] [1][1] [1][2] [1][3] [1][4] // row 1 
   [2][0] [2][1] [2][2] [2][3] [2][4] // row 2

사실, 자바스크립트에서 진정한 2차원 배열은 없습니다. 다차원 배열을 흉내내는 겁니다. let arr = [][]; 이와 같이 한 번에 2차원 배열 선언이 불가능합니다. 약간의 트릭을 통하여 2차원 배열과 비슷한 배열을 만들 수 있습니다. 만드는 방식도 다양합니다.

👉🏻 자바스크립트에서 2차원 배열 만들기

전체 행과 열을 순회하기 위해서는 다중 반복문을 통하여 가능하며 다차원 구성으로 접근이 어려워진 데이터의 경우, ES6 문법인 flat()을 활용하여 차원을 얕게 만드는 것도 가능합니다.


주요 메서드

메소드설명
concat배열을 합치고, 병합된 배열의 사본 리턴
everyfalse가 리턴되기 전까지 배열의 각 원소별로 함수를 호출
filter지정된 함수의 결과 값을 true로 만드는 원소들로만 구성된 배열 리턴
forEach배열의 각 원소를 순회하며 지정된 함수 실행
join배열을 하나의 문자열로 합침
indexOf특정 원소의 인덱스를 찾아 리턴
lastIndexOf검색 조건에 부합하는 가장 마지막 원소를 찾아 인덱스 리턴
map배열의 각 원소별로 지정된 함수를 실행한 후 그 결과로 구성된 새로운 배열을 리턴
reverse배열의 순서를 거꾸로 바꿈
slice지정된 인덱스로 부터 원소를 잘라 새로운 배열 리턴
sometrue가 리턴되기 전까지 배열의 각 원소별로 함수를 호출
sort배열의 원소를 알파벳 순으로 또는 지정된 함수에 따른 순서로 정렬
toString배열을 문자열으로 바꾸어 반환
valueOf배열을 문자열으로 바꾸어 반환

좋은 웹페이지 즐겨찾기