Array

김수정·2020년 4월 6일
1

배열이란

배열은 객체에 속해 있는 자료구조입니다. 객체는 키로 구분된 데이터 집합이나 복잡한 개체를 저장할 수 있고, 배열은 키를 인덱스로 사용하여 순서가 있는 컬렉션을 저장할 때 사용합니다. 배열도 객체처럼 참조를 통해 복사가 이루어집니다.

다차원 배열
배열의 요소로 배열이 오는 것입니다. 행렬을 저장하는 용도로 쓰입니다.

let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];
alert( matrix[1][1] ); // 5, 중심에 있는 요소

배열 만들기

배열과 유사한 것들에 대해 알아봅시다. 유사배열은 배열은 아니지만 이터러블 객체 일수는 있습니다.

  • 이터러블 객체 -> 반복이 가능
  • 배열 -> 배열 메서드 사용 가능

Array.from(arrayLike[, mapFn[, thisArg]])
유사배열이나 이터레이터 객체 등 배열이 아닌 요소를 배열로 만들기 위해 사용하는 메서드입니다.
arrayLike를 얕게 복사하여 새로운 배열을 리턴합니다.
전개 연산자로 배열을 만들 수도 있지만 이터러블 객체에서만 동작하기 때문에 일반적으로 from을 더 많이 씁니다.

console.log(Array.from([1, 2, 3], x => x + x));
// expected output: Array [2, 4, 6]

배열 다루기

배열 선언

let arr = new Array();
let arr = [];

요소 얻기

let fruits = ["Apple", "Orange", "Plum"];

alert( fruits[0] ); // Apple

요소 수정하기

let fruits = ["Apple", "Orange", "Plum"];

fruits[2] = 'Pear'; // 배열이 ["Apple", "Orange", "Pear"]로 바뀜

요소 추가하기

let fruits = ["Apple", "Orange", "Pear"];

fruits[3] = 'Lemon'; // 배열이 ["Apple", "Orange", "Pear", "Lemon"]로 바뀜

배열의 크기

length 배열의 크기를 나타내지만 동작 원리는 아주 다릅니다.
배열 내 요소의 개수로 표시되는 것이 아니라 가장 큰 인덱스에 1을 더한 값이므로 요소가 한 개여도 그 요소가 3번 인덱스에 있다면 이 배열의 length는 4가 됩니다.
또한, length값을 덮어쓸 수가 있어서 원래 배열의 개수보다 짧게 바꾸면 다시 복구되지 않습니다.

let fruits = ["Apple", "Orange", "Plum"];

alert( fruits.length ); // 3
fruits.length = 0; // 배열 초기화

배열 메서드

배열 추가하기

arr.push(value1,..valueN): [원본 배열 데이터 수정] 배열 끝에 요소를 추가합니다. 여러 개 가능.

let fruits = ["Apple", "Orange"];

fruits.push("Pear", "Peach");
alert( fruits ); // Apple, Orange, Pear, Peach

arr.unshift(value1,..valueN): [원본 배열 데이터 수정] 배열 앞에 요소를 추가합니다. 여러 개 가능.

let fruits = ["Orange", "Pear"];

fruits.unshift('Apple', 'peach');
alert( fruits ); // Apple, peach, Orange, Pear

arr.concat(arg1, arg2...): [원본 배열 데이터 보존]
arr요소와 인수 안에 있는 요소들을 모은 새로운 배열을 반환합니다. 인수가 배열을 경우 배열의 모든 요소를 복사합니다.

let arr = [1, 2];

// arr의 요소 모두와 [3,4]의 요소 모두를 한데 모은 새로운 배열이 만들어집니다.
alert( arr.concat([3, 4]) ); // 1,2,3,4

// arr의 요소 모두와 [3,4]의 요소 모두, [5,6]의 요소 모두를 모은 새로운 배열이 만들어집니다.
alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6

// arr의 요소 모두와 [3,4]의 요소 모두, 5와 6을 한데 모은 새로운 배열이 만들어집니다.
alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6

만일, 객체일 경우 객체의 프로퍼티들을 배열의 값으로 합치고 싶다면 객체에 Symbol.isConcatSpreadable이 true면 됩니다.

let arr = [1, 2];

let arrayLike = {
  0: "something",
  1: "else",
  [Symbol.isConcatSpreadable]: true,
  length: 2
};

alert( arr.concat(arrayLike) ); // 1,2,something,else

배열 삭제하기

arr.pop(): [원본 배열 데이터 수정] 배열의 끝요소를 제거하고, 제거한 요소를 반환합니다.

let fruits = ["Apple", "Orange", "Pear"];

alert( fruits.pop() ); // remove "Pear" and alert it
alert( fruits ); // Apple, Orange

arr.shift(): [원본 배열 데이터 수정] 배열 앞 요소를 제거하고, 제거한 요소를 반환합니다.

let fruits = ["Apple", "Orange", "Pear"];

alert( fruits.shift() ); // remove Apple and alert it
alert( fruits ); // Orange, Pear

배열을 문자열로 변환하기

객체에 존재하는 Symbol.toPrimitivevalueOf는 없지만 arr.toString() 메서드가 구현되어 있어 요소를 쉼표로 구분한 문자열이 반환됩니다. 자동으로 문자열로 변환됩니다.
toString은 [원본 배열 데이터 보존]하는 메서드입니다.

let arr = [1, 2, 3];

alert( arr ); // 1,2,3
alert( String(arr) === '1,2,3' ); // true
alert( arr.toString() ); // 1,2,3
alert( [] + 1 ); // "1"
alert( [1] + 1 ); // "11"
alert( [1,2] + 1 ); // "1,21"

원하는 위치의 배열 요소 삭제, 대체하기

arr.splice(index[, deleteCount, elem1, ..., elemN])[원본 배열 데이터 수정]
index: 시작할 인덱스. 음수 인덱스를 사용하면 끝에서부터 셈.
deleteCount: 지울 요소 개수
elem1~emenN: 지운 곳에 대체할 요소들
리턴: 삭제한 요소로 구성된 배열

let arr = ["I", "study", "JavaScript"];

// 인덱스 2부터
// 0개의 요소를 삭제합니다.
// 그 후, "complex"와 "language"를 추가합니다.
arr.splice(2, 0, "complex", "language");

alert( arr ); // "I", "study", "complex", "language", "JavaScript"

배열 복사 및 서브배열 추출하기

arr.slice([start], [end])[원본 배열 데이터 보존]
startIndex부터 endIndex-1까지의 요소를 복사한 새로운 배열을 반환합니다.
음수 인덱스라면 뒤에서부터 계산합니다.
아무 인자를 넘기지 않으면 그대로 복사 가 됩니다.

let arr = ["t", "e", "s", "t"];

alert( arr.slice(1, 3) ); // e,s (인덱스가 1인 요소부터 인덱스가 3인 요소까지를 복사(인덱스가 3인 요소는 제외))
alert( arr.slice(-2) ); // s,t (인덱스가 -2인 요소부터 제일 끝 요소까지를 복사)

배열 탐색하기

원시형 데이터를 배열 내에서 탐색할 때
arr.indexOf(item, from): [원본 배열 데이터 보존] from index부터 시작해 item을 찾습니다. 요소를 발견하면 해당 인덱스 반환, 없으면 -1을 반환합니다. 여러 번 포함되어 있으면 처음 발견된 인덱스로 반환합니다.
arr.lastIndexOf(item, from): [원본 배열 데이터 보존] 위 메서드와 동일한데 from index 위치가 끝에서 부터 시작합니다.
arr.includes(item, from): from index부터 시작해 item이 있는지 여부 검색합니다. 있으면 true를 반환합니다.

이들은 '===' 비교를 하며, includes는 NaN까지도 제대로 처리합니다.

let arr = [1, 0, false];

alert( arr.indexOf(0) ); // 1
alert( arr.indexOf(false) ); // 2
alert( arr.indexOf(null) ); // -1

alert( arr.includes(1) ); // true

참조형 데이터를 배열 내에서 탐색할 때
arr.find((item[, index[, array]]) => {}[, thisArg]): 콜백함수의 반환 값을 true로 만드는 단 하나 의 요소만 찾습니다. 원하는 요소를 찾으면 해당 요소를 반환합니다. 없으면 undefined를 반환합니다.
arr.findIndex((item[, index[, array]]) => {}[, thisArg]): 위와 동일하나 일치하는 인덱스를 반환하고, 없으면 -1을 반환하는 점만 다릅니다.

let users = [
  {id: 1, name: "John"},
  {id: 2, name: "Pete"},
  {id: 3, name: "Mary"}
];

let user = users.find(item => item.id == 1);
alert(user.name); // John

arr.filter((item[, index[, array]]) => {}): [원본 배열 데이터 보존] find와 동일한데 filter는 조건에 맞는 전체 요소를 담은 배열을 반환합니다.

let users = [
  {id: 1, name: "John"},
  {id: 2, name: "Pete"},
  {id: 3, name: "Mary"}
];

// 앞쪽 사용자 두 명을 반환합니다.
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2

배열을 변형하기

arr.map((item[, index[, array]]) => {}[,thisArg]): [원본 배열 데이터 보존] arr에 있는 item 전체를 대상으로 콜백함수를 호출하고, 함수 호출 결과를 배열로 반환해줍니다.

const a = [ 1, 2, 3 ]
const b = a.map(function (v, i, arr) {
    console.log(v, i, arr, this)
    return this[0] + v
}, [ 10 ])

arr.sort((a, b) => {return required}): [원본 배열 데이터 수정] 요소를 문자열로 취급하여 재정렬합니다. 따라서 새로운 정렬 기준을 만드려면 인수에 함수를 넘겨주어야 합니다. 숫자 비교는 양수를 리턴하면 첫 번째 인수가 크다, 음수를 리턴하면 두 번째 인수가 크다는 규칙이 있다는 것과 문자 비교는 a.localeCompare(b)를 사용할 것을 권합니다.

function compareNumeric(a, b) {
  if (a > b) return 1;
  if (a == b) return 0;
  if (a < b) return -1;
}

let arr = [ 1, 2, 15 ];
arr.sort(compareNumeric);
alert(arr);  // 1, 2, 15

arr.reverse(): [원본 배열 데이터 수정] arr의 요소를 역순으로 정렬시켜줍니다.

let arr = [1, 2, 3, 4, 5];
arr.reverse();

alert( arr ); // 5,4,3,2,1

arr.join(glue) [원본 배열 데이터 보존] 배열을 glue를 넣어 문자열로 합쳐줍니다.

let arr = ['Bilbo', 'Gandalf', 'Nazgul'];

let str = arr.join(';'); // 배열 요소 모두를 ;를 사용해 하나의 문자열로 합칩니다.
alert( str ); // Bilbo;Gandalf;Nazgul

arr.reduce((accumulator, item[, index[, array]]) => {} [, initialValue]) [원본 배열 데이터 보존] 배열을 기반으로 값 하나를 도출할 때 사용합니다. 배열을 순차적으로 돌며 함수를 호출하고 함수를 호출한 결과를 첫 번째 인수로 넘겨 값을 계속 새로 갱신합니다.

  • initialValue: 함수 최초 호출 시 사용되는 초기값. 생략시 첫번째 인자가 자동 지정되며, 이 경우 item은 두번째 인자부터 배정됩니다. 그러나 빈 배열일 경우 에러가 나므로 초기값을 설정할 것을 권장합니다.
  • callback
    • accumulator: 이전 함수 호출의 결과. 누적된 계산값
    • item: 현재 배열 요소
    • index: 현재 배열 인덱스
    • array: 원본 배열
      arr.reduceRight()는 리듀스와 동일합니다만 오른쪽부터 시작한다는 점이 다릅니다.
const arr = [ 1, 2, 3 ]
const res = arr.reduce(function (p, c, i, arr) {
  console.log(p, c, i, arr, this)
  return p + c
}, 10)

arr.fill(value, start, end) [원본 배열 데이터 수정] start(기본값 0)부터 end까지 value를 채워 넣습니다. value에 객체를 받으면 참조복사로 배열을 채웁니다.

[1, 2, 3].fill(4, 1);            // [1, 4, 4]
Array(3).fill(4);                // [4, 4, 4]
[].fill.call({ length: 3 }, 4);  // {0: 4, 1: 4, 2: 4, length: 3}

var arr = Array(3).fill({}); // [{}, {}, {}]
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]

arr.copyWithin(target, start, end) [원본 배열 데이터 수정] start부터 end-1 까지 복사하여 target위치에 붙여넣습니다.

[1, 2, 3, 4, 5].copyWithin(0, 3); // [4, 5, 3, 4, 5]

thisArg
함수를 호출하는 대부분의 배열 메서드에서 마지막 매개변수에 thisArg가 있습니다. 이는 콜백함수의 this를 지정해주는 역할을 합니다.
만일 어떤 객체의 메소드를 콜백함수로 실행하려고 할 때, 그 this를 지정해 주는 식입니다.

let army = {
  minAge: 18,
  maxAge: 27,
  canJoin(user) {
    return user.age >= this.minAge && user.age < this.maxAge;
  }
};
let users = [
  {age: 16},
  {age: 20},
  {age: 23},
  {age: 30}
];
// army.canJoin 호출 시 참을 반환해주는 user를 찾음
let soldiers = users.filter(army.canJoin, army);
alert(soldiers.length); // 2
alert(soldiers[0].age); // 20
alert(soldiers[1].age); // 23

배열 여부 알아내기

자바스크립트에서 배열은 독립된 자료형이 아니기 때문에 typeof 등으로 알아낼 수 없습니다.
따라서 Array.isArray(value)를 사용하여 알아냅니다.

alert(Array.isArray({})); // false
alert(Array.isArray([])); // true

배열 확인하기

arr.every((item, index) => {}) [원본 배열 데이터 보존] 함수의 반환값을 참으로 만드는 요소가 하나라도 있는지 확인. boolean값을 반환합니다.

arr.some((item, index) => {}) [원본 배열 데이터 보존] 모든 요소가 함수의 반환값을 참으로 만드는지 확인. bool반환.

배열과 반복문

for

인덱스를 사용해 배열 요소를 순환합니다.

let arr = ["Apple", "Orange", "Pear"];

for (let i = 0; i < arr.length; i++) {
  alert( arr[i] );
}

for..of

배열의 요소를 대상으로 순환합니다.

let fruits = ["Apple", "Orange", "Plum"];

// 배열 요소를 대상으로 반복 작업을 수행합니다.
for (let fruit of fruits) {
  alert( fruit );
}

for..in

객체에 최적화된 반복문이기 때문에 배열엔 함께 쓰지 않는 것을 추천합니다. 더 느리고 필요 없는 프로퍼티까지 포함되는 불상사가 생길 수 있습니다.

forEach

[원본 배열 데이터 보존] for문과 같은 동작.
Array.prototype.forEach(callback[, thisArg])

  • callback: function (currentValue[, index[, originalArray]])
    • currentValue: 현재값
    • index: 현재 인덱스
    • originalArray: 원본 배열
  • thisArg: this에 할당할 대상. 생략시 global객체
const a = [ 1, 2, 3 ]
a.forEach(function (v, i, arr) {
    console.log(v, i, arr, this)
}, [ 10, 11, 12 ])
profile
정리하는 개발자

1개의 댓글

comment-user-thumbnail
2020년 5월 13일

글 잘 읽었어요! some이랑 every 부분 반대로 적은게 아닌가 싶네요!!

답글 달기