5.22 Javascript Array

배열

배열(array)는 1개의 변수에 여러 개의 값을 순차적으로 저장할 때 사용한다. 자바스크립트의 배열은 객체이며 유용한 내장 메서드를 포함하고 있다.

1. 배열의 생성

1.1 배열 리터럴

0개 이상의 값을 쉼표로 구분하여 대괄호([])로 묶는다. 첫번째 값은 인덱스 ‘0’으로 읽을 수 있다. 존재하지 않는 요소에 접근하면 undefined를 얻게 된다.

var emptyArr = [];

var numbersArr = [
  'zero', 'one', 'two', 'three', 'four',
  'five', 'six', 'seven', 'eight', 'nine'
];

console.log(emptyArr[1]);       // undefined
console.log(numbersArr[1]);     // 'one'
console.log(emptyArr.length);   // 0
console.log(numbersArr.length); // 10
console.log(typeof numbersArr); // object

위의 예를 객체 리터럴로 유사하게 표현하면 다음과 같다.

var numbersObject = {
  '0': 'zero',  '1': 'one',   '2': 'two',
  '3': 'three', '4': 'four',  '5': 'five',
  '6': 'six',   '7': 'seven', '8': 'eight',
  '9': 'nine'
};

배열 리터럴은 객체 리터럴과 달리 속성명이 없고 각 요소의 값만이 존재한다. 객체는 속성에 접근하기 위해 대괄호 표기법과 마침표 표기법을 사용하지만 배열은 대괄호 내에 접근하고자 하는 요소의 인덱스만 넣어주면 된다. 인덱스은 0부터 시작한다.

두 객체의 근본적 차이는 numbersArrArray.prototype을 상속받았으나 numbersObjectObject.prototype을 상속 받았다는 것이다. Array 객체는 다양한 메서드(e.g. sort)와 속성(e.g. length)을 제공한다.

object prototype & array prototype

var emptyArr = [];
var emptyObj = {};

console.dir(emptyArr.__proto__);
console.dir(emptyObj.__proto__);

object prototype & array prototype

대부분의 언어에서 배열의 요소들은 모두 같은 데이터 타입이어야 하지만, 자바스크립트 배열은 어떤 데이터 타입의 조합이라도 포함할 수 있다.

var misc = [
  'string', 98.6, true, false, null, undefined, ['nested', 'array'], {object: true}, NaN, Infinity
];

misc.length   // 10

1.2 Array() 생성자 함수

배열은 일반적으로 배열 리터럴 방식으로 생성하지만 배열 리터럴 방식도 결국 내장 함수 Array() 생성자 함수로 배열을 생성하는 것을 단순화시킨 것이다. Array() 생성자 함수는 Array.prototype.constructor 속성으로 접근할 수 있다.

Array() 생성자 함수는 매개변수의 갯수에 따라 다르게 동작한다.

매개변수가 1개이고 숫자인 경우

new Array(arrayLength)

매개변수로 전달된 숫자를 length 값으로 가지는 빈 배열 생성

var arr = new Array(2);
console.log(arr.length, arr); // 2 [undefined, undefined]

그 외의 경우

new Array(element0, element1[, ...[, elementN]])

매개변수로 전달된 값을 요소로 가지는 배열을 생성

var arr = new Array(1, 2, 3);
console.log(arr.length, arr); // 3 [1, 2, 3]

2. 배열 요소의 추가와 삭제

2.1 배열 요소의 추가

객체가 동적으로 속성을 추가할 수 있는 것처럼 배열도 동적으로 요소를 추가할 수 있다. 이때 순서에 맞게 값을 저장할 필요는 없고 필요한 인덱스 위치에 값을 저장할 수 있다. 값이 할당되지 않은 인덱스 위치의 요소의 값은 undefined가 되고 배열의 길이(length)는 최종 인덱스 위치의 기준으로 산정된다.

var emptyArr = [];
console.log(emptyArr[0]); // undefined

emptyArr[0] = 'one';
emptyArr[3] = 'three';
emptyArr[7] = 'seven';

console.dir(emptyArr);

2.2 배열 요소의 삭제

배열은 객체이기 때문에 배열의 요소를 삭제하기 위해 delete 연산자를 사용할 수 있다. 이때 해당 요소가 삭제되는 것이 아니라 요소 값이 삭제되어 undefined가 된다.

해당 요소를 완전히 삭제하기 위해서는 Array.prototype.splice() 메서드를 사용한다.

var numbersArr = ['zero', 'one', 'two', 'three'];

// 요소의 값만 삭제된다
delete numbersArr[2]; // ['zero', 'one', undefined, 'three']
console.log(numbersArr);

// 요소 일부를 삭제 (배열 시작점, 삭제할 요소수)
numbersArr.splice(2, 1); // ['zero', 'one', 'three']
console.log(numbersArr);

3. 배열 요소의 열거

객체의 속성을 열거할 때 for in 문을 사용한다. 배열 역시 객체이므로 for in 문을 사용할 수 있다

그러나 배열은 객체이기 때문에 속성을 가질 수 있다. for in 문을 사용하면 불필요한 속성까지 출력될 수 있고 요소들의 순서를 보장하지 않으므로 배열을 열거하는데 적합하지 않다.

따라서 배열 요소의 열거에는 for 문을 사용하는 것이 좋다.

var numbersArr = ['zero', 'one', 'two', 'three'];
numbersArr.foo = 10;

for (var prop in numbersArr) {
  console.log(prop, numbersArr[prop]);
}

for (var i = 0; i < numbersArr.length; i++) {
  console.log(i, numbersArr[i]);
}

for in 문은 요소들의 순서를 보장하지 않으므로 배열을 열거하는데 적합하지 않다.

4. Array Property

4.1 Array.length

length 속성은 요소의 갯수(배열의 길이)를 나타낸다. Array.length는 양의 정수이며 232미만이다.

하지만 배열에 실제로 존재하는 요소의 갯수와 반드시 일치하는 것은 아니다. 현재 length 속성보다 더 큰 인덱스로 항목을 추가하면 length 속성은 새로운 항목을 추가할 수 있도록 자동으로 늘어난다. 즉 length 속성은 가장 큰 인덱스에 1을 더한 것과 같다.

var myArray = [];
console.log(myArray.length); // 0

myArray[1000] = true;  // [ , , ... , , true ]

console.log(myArray.length); // 1001
console.log(myArray[0]);     // undefined

length 속성은 명시적으로 값을 변경할 수 있다. 만약 length 속성의 값을 현재 보다 작게 설정하면 설정한 값보다 크거나 같은 인덱스에 해당하는 요소는 모두 삭제된다.

var numbersArr = [
  'zero', 'one', 'two', 'three', 'four',
  'five', 'six', 'seven', 'eight', 'nine'
];

// 배열 길이의 명시적 설정
numbersArr.length = 3; // [ 'zero', 'one', 'two' ]

// 배열 끝에 새 요소 추가
numbersArr[numbersArr.length] = 'san'; // [ 'zero', 'one', 'two', 'san' ]
console.log('length: '+numbersArr.length, numbersArr);

numbersArr.length = 5; // [ 'zero', 'one', 'two', 'san', undefined ]
console.log('length: '+numbersArr.length, numbersArr);

// 배열 끝에 새 요소 추가
numbersArr.push('go'); // [ 'zero', 'one', 'two', 'san', undefined, 'go' ]
console.log('length: '+numbersArr.length, numbersArr);

Array.prototype.push() 메서드는 매개변수로 전달된 값들을 배열의 마지막에 추가한다. 이것은 결국 배열의 마지막 인덱스 위치에 값을 할당한 것과 같다.

5. Array Method

5.1 Array.isArray()

객체가 배열이면 true, 배열이 아니면 false를 반환한다.

// true
Array.isArray([]);
Array.isArray([1, 2]);
Array.isArray(new Array());

// false
Array.isArray();           
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(1);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);

5.2 Array.prototype.indexOf()

배열에서 인수로 지정된 요소를 검색하여 인덱스를 반환한다. 중복되는 요소가 있는 경우 첫번째 인덱스만 반환된다. 만일 해당하는 요소가 없는 경우, -1을 반환한다.

var arr = [1, 2, 2, 3];
arr.indexOf(2); // 1
arr.indexOf(4); // -1

5.3 Array.prototype.concat(item…)

인수로 넘어온 값들을 자신의 복사본에 추가한 새로운 배열을 반환한다. 이때 인수는 배열 또는 값이다.

var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];

var c = a.concat(b); // ['a', 'b', 'c', 'x', 'y', 'z']

var d = a.concat('String'); // ['a', 'b', 'c', 'String']

var e = a.concat(b, true); // ['a', 'b', 'c', 'x', 'y', 'z', true]

console.log(a);

5.4 Array.prototype.join()

배열 요소 전체를 연결하여 문자열을 만든다. 기본구분자는 ‘,’이다.

str = arr.join([separator = ','])

Array.prototype.join() 메서드는 + 연산자보다 빠르다.

var a = ['a', 'b', 'c'];
a.push('d');
var c = a.join();     // --> 'a,b,c,d';
var d = a.join('');   // --> 'abcd';
var e = a.join(':');  // --> 'a:b:c:d';

5.5 Array.prototype.pop()

poppush와 함께 배열을 스택(LIFO: Last In First Out)처럼 동작하게 한다. pop 메서드는 배열에서 마지막 요소를 제거하고 제거한 요소를 반환한다. 만약 빈 배열일 경우 undefined를 반환한다.

var a = ['a', 'b', 'c'];
var c = a.pop();

console.log(a); // a --> ['a', 'b']
console.log(c); // c --> 'c'

pop 메서드를 호출한 배열 자체가 수정된다.

5.6 Array.prototype.push(item…)

인수로 넘어온 항목을 배열의 끝에 추가한다. concat 메서드와 다르게 배열 자체를 수정하여 넘어온 인수 전체를 배열에 추가한다. 반환값은 배열의 새로운 length 값이다.

var a = ['a', 'b', 'c'];
var b = ['x', 'y', 'z'];
var c = a.push(b, true);
console.log(a); // a --> ['a', 'b', 'c', ['x', 'y', 'z'], true]
console.log(c); // c --> 5;

배열의 마지막에 값을 추가 할 때는 Array.prototype.push(), 선두에 추가 할 때는 Array.prototype.unshift(), 중간에 추가할 때는 Array.prototype.splice() 메서드를 사용한다.

단, push, unshift 메서드는 사용하기 간편하나 performance 면에서는 좋은 방법은 아니다.

var arr = [1,2,3,4,5];

arr.push(6);
arr[arr.length] = 6; // 43% faster in Chrome 47.0.2526.106 on Mac OS X 10.11.1

arr.unshift(0);
[0].concat(arr); // 98% faster in Chrome 47.0.2526.106 on Mac OS X 10.11.1

5.7 Array.prototype.reverse()

배열 요소의 순서를 반대로 변경한다. 반환값은 배열이다.

var a = ['a', 'b', 'c'];
var b = a.reverse();
// a,b --> ['c', 'b', 'a']

5.8 Array.prototype.shift()

shiftpush와 함께 배열을 큐(FIFO: First In First Out)처럼 동작하게 한다. 배열에서 첫요소를 제거하고 제거한 요소를 반환한다. 만약 빈 배열일 경우 undefined를 반환한다.

var a = ['a', 'b', 'c'];
var c = a.shift();
// a --> ['b', 'c']
// c --> 'a'

Array.prototype.pop()은 마지막 요소를 제거하고 제거한 요소를 반환한다.

5.9 Array.prototype.slice(start, end)

배열의 특정 부분에 대한 복사본을 생성한다.

첫번째 매개변수 start에 해당하는 인덱스를 갖는 요소부터 매개변수 end에 해당하는 인덱스를 가진 요소 전까지 복사된다.

  • 매개변수
start
음수인 경우 배열의 끝에서의 인덱스를 나타낸다. 예를 들어 slice(-2)는 배열의 마지막 2개의 요소를 반환한다.
end
옵션이며 기본값은 length 값이다.
var items = ['a', 'b', 'c'];

// items[0]부터 items[1] 이전(items[1] 미포함)까지 반환
var res1 = items.slice(0, 1);

// items[1]부터 items[2] 이전(items[2] 미포함)까지 반환
var res2 = items.slice(1, 2);

// items[1]부터 이후의 모든 요소 반환
var res3 = items.slice(1);

// 인자가 음수인 경우 배열의 끝에서 2개의 요소를 반환
var res4 = items.slice(-2);

// 모든 요소를 반환
var res5 = items.slice();

// slice는 복사본을 반환한다. 원본은 변경되지 않는다.
console.log(items); // [ 'a', 'b', 'c' ]

console.log(res1);  // [ 'a' ]
console.log(res2);  // [ 'b' ]
console.log(res3);  // [ 'b', 'c' ]
console.log(res4);  // [ 'b', 'c' ]
console.log(res5);  // [ 'a', 'b', 'c' ]

5.10 Array.prototype.splice(start, deleteCount, item…)

기존의 배열의 내용을 추가 또는 제거하고 그 부분을 새로운 항목으로 대체한다.

  • 매개변수
start
배열에서의 시작 위치이다
deleteCount
시작 위치(start)부터 제거할 요소의 수이다.
item
삭제한 위치에 추가될 요소들이다. (옵션)
  • 반환값
    삭제한 요소들을 가진 배열이다.

이 메서드의 가장 일반적인 사용은 배열에서 요소를 삭제할 때다.

var items = ['one', 'two', 'three', 'four'];

// items[1]부터 2개의 요소를 제거하고 제거된 요소를 반환
var res = items.splice(1, 2);

console.log(items); // [ 'one', 'four' ]
console.log(res);   // [ 'two', 'three' ]

배열에서 요소를 삭제하고 삭제한 위치에 다른 요소를 추가한다.

var items = ['one', 'two', 'three', 'four'];

// items[1]부터 2개의 요소를 제거하고 그자리에 새로운 요소를 추가한다. 제거된 요소가 반환된다.
var res = items.splice(1, 2, 'x', 'y');

console.log(items); // [ 'one', 'x', 'y', 'four' ]
console.log(res);   // [ 'two', 'three' ]

배열 중간에 새로운 요소를 추가할 때도 사용된다.

var items = ['one', 'two', 'three', 'four'];

// items[1]부터 0개의 요소를 제거하고 그자리(items[1])에 새로운 요소를 추가한다. 제거된 요소가 반환된다.
var res = items.splice(1, 0, 'x');

console.log(items); // [ 'one', 'x', 'two', 'three', 'four' ]
console.log(res);   // [ ]

배열 중간에 새로운 배열을 추가할 때도 사용된다.

var items = ['one', 'four'];

// items[1]부터 0개의 요소를 제거하고 그자리(items[1])에 새로운 배열를 추가한다. 제거된 요소가 반환된다.
var res = Array.prototype.splice.apply(items, [1, 0].concat(['two', 'three']));

console.log(items); // [ 'one', 'two', 'three', 'four' ]
console.log(res);   // [ ]

배열의 일부를 반환할 수도 있다.

var items = ['one', 'two', 'three', 'four'];

// items[1]부터 2개의 요소를 제거하고 제거된 요소를 반환된다.
var res = items.splice(1, 2);

console.log(items); // [ 'one', 'four' ]
console.log(res);   // [ 'two', 'three' ]

5.11 Array.prototype.sort(comparefunc)

배열의 내용을 적절하게 정렬한다.

var fruits = ["Banana", "Orange", "Apple", "Mango"];

// The sort() method sorts the items of an array.
// ascending
fruits.sort();
console.log(fruits); // [ 'Apple', 'Banana', 'Mango', 'Orange' ]

// descending
fruits.reverse();
console.log(fruits); // [ 'Orange', 'Mango', 'Banana', 'Apple' ]

var points = [40, 100, 1, 5, 25, 10];

points.sort();
console.log(points); // [ 1, 10, 100, 25, 40, 5 ]

// Syntax : array.sort(compareFunction)

// Sort numbers in an array in ascending order:
points.sort(function(a, b){return a-b});
console.log(points); // [ 1, 5, 10, 25, 40, 100 ]

// Get the lowest value in an array:
console.log(points[0]); // 1

// Sort numbers in an array in descending order:
points.sort(function(a, b){return b-a});
console.log(points); // [ 100, 40, 25, 10, 5, 1 ]

// Get the highest value in an array:
console.log(points[0]); // 100

5.12 Array.prototype.map()

배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수를 실행하고 그 결과가 반영된 새로운 배열을 반환한다. 콜백함수의 인자로 요소값, 요소 인덱스, 순회할 배열을 전달할 수 있다.

var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
console.log("roots is : " + roots );

두번째 인자로 this를 전달할 수 있다.

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function(arr) {
  return arr.map(function(x) {
    // x는 요소값이다.
    return this.prefix + x; // 2번째 인자 this를 전달하지 않으면 this === window
  }, this);
};

var pre = new Prefixer('-webkit-');
var preArr = pre.prefixArray(['linear-gradient', 'border-radius']);
console.log(preArr);
// [ '-webkit-linear-gradient', '-webkit-border-radius' ]

ES6의 Arrow function를 사용하면 this를 Prefixer.prototype에 bind하기 때문에 두번째 인자로 this를 생략하여도 동일한 동작을 한다.

5.13 Array.prototype.forEach()

배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수를 실행한다. 콜백함수의 인자로 요소값, 요소 인덱스, 순회할 배열을 전달할 수 있다. 일반 for 구문에 비해 성능이 좋지는 않다.

var total = 0;

[1, 3, 5, 7, 9].forEach(function(element, index, array) {
  console.log('[' + index + '] = ' + element);
  total += element;
})

console.log(total);

두번째 인자로 this를 전달할 수 있다.

function Counter() {
  this.sum = 0;
  this.count = 0;
}
Counter.prototype.add = function(array) {
  array.forEach(function(entry) {
    this.sum += entry; // 2번째 인자 this를 전달하지 않으면 this === window
    ++this.count;
  }, this);
};

var obj = new Counter();
obj.add([2, 5, 9]);
console.log(obj.count);  // 3
console.log(obj.sum);    // 16

ES6의 Arrow function를 사용하면 this를 Counter.prototype에 bind하기 때문에 두번째 인자로 this를 생략하여도 동일한 동작을 한다.

5.14 Array.prototype.filter()

배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수의 실행 결과가 true인 요소값만을 모은 새로운 배열을 반환한다.

배열에서 특정 케이스만 필터링 조건으로 추출하여 새로운 배열을 만들고 싶을 때 사용한다.

콜백함수의 인자로 요소값, 요소 인덱스, 순회할 배열을 전달할 수 있다.

var result = [1, 2, 3, 4, 5].filter(function(element, index, array) {
  console.log('[' + index + '] = ' + element);
  return element % 2; // 홀수만을 필터링한다 (1은 true로 평가된다)
})

console.log(result);

filter()도 map(), forEach()와 같이 두번째 인자로 this를 전달할 수 있다.

5.15 Array.prototype.reduce()

배열을 순회하며 각 요소에 대하여 이전의 콜백함수 실행 반환값을 전달하여 콜백함수를 실행하고 그 결과를 반환한다.

/*
previousValue: 이전 콜백의 반환값
currentValue : 요소값
currentIndex : 인덱스
array        : 순회할 배열
*/
var result = [1, 2, 3, 4, 5].reduce(function(previousValue, currentValue, currentIndex, array) {
  console.log(previousValue + '+' + currentValue + '=' + (previousValue + currentValue));
  return previousValue + currentValue; // 결과는 다음 콜백의 첫번째 인자로 전달된다
});

console.log(result); // 15: 1~5까지의 합
/*
1: 1+2=3
2: 3+3=6
3: 6+4=10
4: 10+5=15
15
*/

5.16 Array.prototype.find()

ES6에서 새롭게 도입된 메서드로 Internet Explorer에서는 지원하지 않는다.

배열을 순회하며 각 요소에 대하여 인자로 주어진 콜백함수를 실행하여 그 결과가 참인 첫번째 요소를 반환한다. 콜백함수의 인자로 요소값, 요소 인덱스, 순회할 배열을 전달할 수 있다.

var array = [
  {id: 1, name: 'Lee'},
  {id: 2, name: 'Kim'},
  {id: 2, name: 'Choi'},
  {id: 3, name: 'Park'}
];

var result = array.find(function(element, index, array) {
  return element.id === 2;
});

// ES6
// const result = array.find(element => element.id === 2;);

console.log(result); // { id: 2, name: 'Kim' }

Reference

Back to top
Close