JAVASCRIPT

배열

걍가영 2019. 7. 23. 18:14

배열

배열은 객체의 일종이지만, 내부적으로 특별하게 취급되어 일반적이 객체들과는 다른 특징을 갖고 있습니다.
배열 안에 들어있는 값들은 요소(element) 혹은 항목(item)이라고 하며, 순서가 있습니다. 프로토타입으로 Array.prototype 객체가 지정되어 있습니다.

typeof []; // 'object'

배열 리터럴

배열은 배열 리터럴(array literal)을 통해서 생성하는 것이 쉽습니다.

const empty  = []; // 빈 배열
const numbers = [1, 2, 3]; // 숫자가 들어있는 배열 
const strings = ['one', 'two', 'three']; // 문자열이 들어있는 배열
const objects = [{prop: 1}, {prop: 2}, {prop: 3}]; // 객체가 들어있는 배열
const mixed = [1, 'one', {prop: 1}, null]; // 종합적으로 들어있는 배열

Array 생성자

Array 생성자 를 통해서도 배열을 생성할 수 있습니다. 주어지는 인수에 따라 두 가지 서로 다른 방식으로 동작을 합니다.

  1. 수 타입의 인수가 하나 주어질 때는 해당 수 만큼의 실이를 갖는 비어있는 배열을 만들어 냅니다.
    만약 인수가 양의 정수가 아니라면 에러를 냅니다.
  2. 이 외에 다른 모양으로 인수가 주어지면 그 인수들을 요소로 갖는 배열을 생성합니다.
new Array(1); // [empty]
new Array(1000); // [empty * 1000]
new Array(1, 2, 3); // [1, 2, 3]

Array.of

일관적이지 못한 동작방신 때문에, Array.of 정적 메소드가 추가되었습니다.

Array.of(1, 2, 3)

// `Array.of` 정적 메소드는 인수가 하나이더라도 그 인수를 요소로 갖는 배열을 반환합니다.
Array.of(1); // [1]

// 생성자는 이런 용도로만 사용하세요.
new Array(1000); // [empty * 1000]

Array.from

유사 배열 객체와 iterable이라는 개념이 있어서, 이에 해당하는 값들은 Array.from 정적 메소드를 통해 배열로 쉽게 변환될 수 있습니다.

// `string` 타입은 래퍼 객체를 통해 iterable로 다루어질 수 있습니다.
Array.from('hello'); // ["h", "e", "l", "l", "o"]

요소 읽기

배열의 각 요소는 인덱스(index) 를 이용해 읽어올 수 있으며, 0 이상의 정수 만이 배열의 인덱스가 될 수 있습니다.
첫번째 요소를 가리키는 인덱스는 1이 아니라 0입니다.

const arr = ['one', 'two', 'three'];
arr[0]; // 'one'
arr[1]; // 'two'
arr[2]; //  'three'
arr[3]; // undefined

요소 수정하기

const arr  = [false, false, false];
arr[1] = true;

console.log(arr); // [false, true, false]

fill 메소드를 사용하면 많은 요소를 같은 값으로 바꾸어 버릴 수도 있습니다.

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

// 전체를 0으로 채우기
arr.fill(0);
console.log(arr); // [0, 0, 0, 0, 0];

// 인덱스 2와 4 사이를 1로 채우기
arr.fill(1, 2, 4);
console.log(arr); // [0,  0, 1, 1, 0];

Array 생성자와 fill 메소드를 사용하면, 큰 배열을 만들고 값을 채워넣는 일을 쉽게 할 수 있습니다.

new Array(1000); // [empty * 1000]
new Array(1000).fill(5); // [5, 5, 5, 5, ...]

배열의 끝 부분에서 요소를 추가/제거하기

push 메소드와 pop 메소드를 사용하면 배열의 끝 부분에서 요소를 추가하거나 제거할 수 있습니다.

const arr = [];
arr.push('one'); // 1 (요소가 추가된 후의 배열의길이를 반환)
arr.push('two',  'three'); // 3
console.log(arr); //  ['one',  'two', 'three']

// 배열의 요소 삭제하기
arr.pop();  // 'three'
arr.pop(); // 'two'
arr.pop();  // 'one'
arr.pop();  // undefined

배열의 시작 부분에서 요소를 추가/제거하기

unshift, shift 메소드를 사용해 배열의 시작 부분에서 요소를 추가하거나 제거할 수도 있습니다.

const arr  = [];
arr.unshift(1); // 1 (요소가 추가된 후의 배열의 길이를 반환)
arr.unshift(2,  3); // 3
console.log(arr); [2, 3, 1]

// 배열의 요소 삭제하기
arr.shift();  //  2
arr.shift();  //  3
arr.shift();  //  1
arr.shift();  //  undefined

요소를 배열 중간에 삽입하기

splice 메소드를 사용하면 배열의 일부분을 통째로 바꿔버릴 수 있습니다.
또한 배열의 중간 부분에 있는 요소를 제거 하는 데도 활용할 수 있습니다.

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

// 인덱스 `1`인 요소부터 `3`개를 바꿔치기 합니다.
arr.splice(1, 3, 'two',  'three', 'four' ); // [2, 3, 4]

//  `splice` 메소드는 바꿔치기를 통해 제거된 요소들을 반환합니다.
console.log(arr); // [1, 'two', 'three', 'four', 5]
const arr = [1, 2, 3, 4, 5];

// 인덱스 `1`인 요소부터 `3`개를 바꿔치기 합니다.
arr.splice(1, 3, 'three');  //  [2, 3, 4]

// `3`개를 꺼낸 자리에 하나의 요소를 삽입합니다.
console.log(arr); // [1, 'three', 5]

splice의 뒤쪽 인수를 생략하면, 요소를 제거할 뿐 배열에 아무것도 삽입하지 않습니다.

const arr = [1, 2, 3, 4, 5];
arr.splice(1, 3); // [2, 3, 4]

console.log(arr); // [1, 5]

splice의 두 번째인수로 0을 사용하면, 특정 위치에 여러 요소를 삽입할수도 있습니다.

// 인덱스가 `1`인 요소 앞에 여러 요소를 추가합니다.
const arr = [1,  5];
arr.splice(1, 0, 2, 3, 4); //  []

console.log(arr); //[1, 2, 3, 4, 5]

배열 뒤집기

배열의 reverse메소드를 호출하면 해당 배열을 거꾸로 뒤집어 버립니다.

const arr = [1, 2, 3];

// `reverse` 메소드는 `arr`을 뒤집은 후, `arr`을 그대로 반환합니다.
arr.reverse(); // [3, 2, 1]

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

배열 정렬하기

배열의 sort 메소드를 통해 원하는 방식대로 배열을 정렬할 수 있습니다. sort 메소드의 인수에는 비교 함수를 넘겨주어야 합니다.
비교 함수는 인수 두 개를 받아서, 아래의 조건에 따라 잘 정렬되도록 적절한 값을 반환해주어야 합니다.

배열을 정렬할 때에는 어떤 값을 기준으로 정렬할 지 를 생각해 본 다음, 정렬함수를 만들 때 오름차순으로 정렬할 지, 내림차순으로 정렬할 지를 생각하면 됩니다.

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

// `sort` 메소드는 `arr`을 비교 함수에 따라 정렬한 뒤, `arr`을 그대로 반환합니다.
arr.sort((x, y) => x - y); // [1, 2, 3, 4, 5]

console.log(arr); //[1, 2, 3, 4, 5] 
const alphabet = ['a', 'b', 'c', 'd'];
alphabet.sort((x,  y) => y.length - x.length);

console.log(alphabet); //['b', 'a', 'd', 'c']

비교 함수를 인수로 넘겨주지 않으면, sort 메소드는 먼저 요소를 전부 문자열로 변환한 후, 유니코드 코드포인트를 비교하는 방식으로 정렬을 합니다. sort 함수를 사용할 때는 꼭 비교함수 를 넘겨줍니다.

[20, 3, 100].sort(); // [100, 20, 3]
['abc', 'def', 'ghr'].sort(); // ['def', 'abc', 'ghr']
[20, 3, 100].sort((x,  y) => x - y); // [3, 20, 100]
['abc', 'def', 'ghr'].sort((x, y) => x.localCompare(y)); //[ 'abc',  'ghr', 'def']

배열의 길이

배열의 길이는 length 속성을 통해 쉽게 확인할 수 있습니다.

const arr = [];
console.log(arr.length); // 0

arr.push(1, 2, 3);
console.log(arr.length); // 3

배열 순회하기

  1. 단순히 배열을 순회하기 위한 목적 for...of 구문 사용, 코드의 간결성이나 속도 측면에서 유리
  2. 인덱스가필요한 경우 forEach 메소드 사용
  3. 코드의 실행 속도가 정말로 중요한 부분은 for

for 구문

for루프를 사용해서 배열의 길이만큼 루프를 돌며, 인덱스를 통해 배열의 요소에 접근합니다.

const arr = [1, 2, 3];

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

forEach 메소드

배열의 forEach 메소드를 사용하면, 배열의 각 요소에 대해 함수를 호출할 수 있습니다.

const arr = [1, 2, 3];

arr.forEach(item  => {
     console.log(`현재 요소 ${item}에 대해 함수가 실행되고 있습니다.`);
});

forEach 메소드에 넘기는 함수에는 총 세 개의 인수가 들어옵니다. 첫 번째는 순회중인 배열의 요소,
두 번재로는 요소의 인덱스, 세 번째로는 순회중인 배열 이 들어옵니다.

const arr = [1, 2, 3];

arr.forEach((item, index, array)=> {
     console.log(`현재 ${index + 1}번째 요소에 대해 함수가 실행되고 있습니다.`);

});

 

for...of 구문

iterable을 순회하기 위해 사용할 수 있습니다.

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

for (let item of arr) {
     console.log(item)
}

배열로부터 새로운 값 생성

배열을 순회하는 것만으로도 이런 작업들을 할 수 있지만, 배열에 내장된 메소드를 사용한다면 훨씬 더 간결한 코드로 같은 작업을 할 수 있습니다.

slice

배열의 일부분의 생당하는 새로운 배열을 반환합니다. slice는 얕은 복사(shallow copy) 를 하므로, 배열 안에 배열 또는 객체가 들어있을 때는 주의해서 사용해야 합니다.

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

// 인덱스 2부터 인덱스 4 사이의 요소들을 가지고 새로운 배열을 생성
const newArr = arr.slice(2, 4); // [3, 4]

// newArr을 조작해도, 원본 배열에는 영향을 미치지 않습니다.
newArr[0] = 5;
console.log(newArr); // [5, 4]
console.log(arr); // [1, 2, 3, 4, 5]

map

map메소드는 배열의 각 요소에 함수를 적용해서, 그 반환값을 요소로 갖는 새로운 배열 을 만듭니다.

const arr  = [1, 2, 3, 4, 5]

// `arr`의 각 요소를 제곱한 값으로 새 배열을 만듭니다.
const newArr = arr.map(item => item ** 2);

console.log(newArr); // [1, 4, 9, 16, 25]
// 인수로 들어온 함수를 호출할 때 세개의 인수를 넘깁니다.
arr.map((item, index, array) => {
     return item * index;
}); 
// [0, 2, 6, 12, 20]

concat

여러 배열을 연결해서 새 배열을 만들때 사용됩니다.

const arr = [1, 2];
arr.concat([3, 4], [5, 6], [7,8]); // [1, 2, 3, 4, 5, 6, 7, 8]

reduce

모든 요소의 값을 종합해서 하나의 값으로 만드는 계산을 할 때 사용합니다. 또한 초기값은 항상 제공해주는 것이 좋습니다.
배열에 대한 계산을 하는 만능 도구

const arr = [1, 2, 3]
arr.reduce((acc, item) => acc +  item, 0); // 6

위 코드에서 일어난 일을 순서대로 정리

  1. 초기값 0과 배열의 첫번째 요소인 1을 인수로 해서 함수를 호출합니다. 즉, acc 매개변수에 0이 대입되고, item매개변수에 1이 대입됩니다. 결과값은 1이 되며 이 값을 누적값(accumulator) 라고 부릅니다
  2. 누적값 1과 배열의 두번째 요소인 2를 인수로 해서 함수를 호출합니다. 결과값이 3이 다시 누적갓이 됩니다.
  3. 누적값 3과 배열의 세번째 요소인 3을 인수로 해서 함수를 호출합니다. 결과값은 6입니다
  4. 더 이성 요소가 남아있지 않으므로 reduce 호출의 결과값은 6이 됩니다.

filter

배열에서 원하는 요소만을 골라내어 새로운 배열을 생성할 수 있습니다. 또한 진리값(boolean)을 반환하는 함수를 주어야 합니다.

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

// 짝수만 골라내기
arr.filter(item => item % 2 === 0); // [2, 4];

join

배열의 요소들을 문자열로 변환 후, 메소드에 주어진 구분자(separstor)를 이용해 하나의 문자열로 결합하여 반환합니다.

const arr = [1, 2, 3]
arr.join('&'); // '1&2&3'

요소 찾기

indexOf & lastIndexOf 메소드

메소드를 사용하면 특정 요소가 배열의 몇 번째에 위치하는 지를 알게 됨
일치하는 요소가 없다면, 두 메소드 모두 -1을 반환

  • indexOf : 배열의 왼쪽부터 처음 만나는 요소의 인덱스 반환
  • lastIndexOf : 배열의의 오른쪽부터 처음 만나는 요소의 인덱스 반환
const arr = ['a', 'b', 'c', 'b', 'a'];

arr.indexOf('b'); // 1
arr.lastIndexOf('b'); // 3

arr.indexOf('z'); // -1
arr.lastIndexOf('z'); // -1

find 메소드 & findIndex

메소드 특정 조건을 만족하는 요소를 찾으며, 왼쪽부터 검사해서 처음 만나는 요소를 찾음

  • find : 요소 자체를 반환. 조건을 만족하는 요소를 찾지 못하면, undefined 반환
  • findIndex : 요소의 인덱스를 반환. 조건을 만족하는 요소를 찾지 못하면, -1 반환
const names = ['Denton', 'Kathleen', 'Ebba', 'Bruce'];

names.find(item => item.length < 6); // 'Ebba'
names.findIndex(item => item.length < 6); // 2

names.find(item => item.length > 8); // undefined
names.findIndex(item => item.length > 8); // -1

배열 특정 조건 만족하는지 판별

배열이 특정 조건을 만족하는지를 나타내는 진리값을 반환

  • includes : 배열이 특정 요소를 포함하고 있는지를 판별. includes가 진리값을 반환
  • every : predicate을 인수로 받아서, 모든 요소가 조건을 만족하는 지를 검사
  • some : predicate을 인수로 받아서, 조건을 만족하는 요소가 하나라도 있는지 검사
// includes
const arr = ['one', 'two', 'three'];

arr.includes('one'); // true
arr.includes('one', 1); // false

// every
const arr = ['one', 'two', 'three'];

arr.every(item => item.length > 2); // true
arr.every(item => item.length > 3); // false

// some
const arr = ['one', 'two', 'three'];

arr.some(item => item.length > 3); // true
arr.some(item => item.length > 5); // false

배열인지 판별

Array.isArray

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