[JavaScript] 배열

thingzoo·2023년 4월 26일
0

JavaScript

목록 보기
4/7
post-thumbnail

배열

순서가 있는 컬렉션을 저장할 때 쓰는 자료구조

  • 배열 요소의 자료형엔 제약이 없음
  • 자바스크립의 배열은 양방향 삽입/삭제 가능
  • 큐와 스택, 덱 자료구조 구현 시 사용

배열 선언

let arr = []; // 가장 많이 쓰이는 방법
let arr = new Array(); // 잘쓰지 않음

Tip

let arr = new Array(2); // 이렇게 하면 배열 [2]가 만들어질까요?
alert( arr[0] ); // undefined가 출력됩니다. 요소가 하나도 없는 배열이 만들어졌네요.
alert( arr.length ); // 길이는 2입니다.
  • new Array(number)를 이용해 만든 배열의 요소는 모두 undefined임
  • 그래서 대부분의 개발자는 대괄호를 이용함

인덱싱

  • 각 배열 요소엔 0부터 시작하는 숫자(인덱스)가 매겨져 있음
  • 이 숫자들은 배열 내 순서를 나타냄
  • 배열 내 특정 요소를 얻고 싶다면, 대괄호 안에 순서를 나타내는 숫자인 인덱스를 넣어주면 됨
  • 같은 방법으로 요소 수정 및 새로운 요소 추가도 가능
let fruits = ["사과", "오렌지", "자두"];

alert( fruits[0] ); // 사과
alert( fruits[1] ); // 오렌지
alert( fruits[2] ); // 자두

length 프로퍼티

배열의 길이를 반환

  • 배열에 무언가 조작을 가하면 length 프로퍼티가 자동으로 갱신됨
  • length 프로퍼티는 배열 내 요소의 개수가 아니라 가장 큰 인덱스에 1을 더한 값
alert( fruits.length ); // 3

쓰기가 가능하다고?

  • length의 값을 수동으로 증가시키면 아무 일도 일어나지 않음
  • 그런데 값을 감소시키면 배열이 잘림! 짧아진 배열은 다시 되돌릴 수 없음!
  • 이런 특징을 이용하면 arr.length = 0;을 사용해 아주 간단하게 배열을 비울 수 있음
let arr = [1, 2, 3, 4, 5];

arr.length = 2; // 요소 2개만 남기고 잘라봅시다.
alert( arr ); // [1, 2]

arr.length = 5; // 본래 길이로 되돌려 봅시다.
alert( arr[3] ); // undefined: 삭제된 기존 요소들이 복구되지 않습니다.

배열의 내부 동작 원리

  • 배열은 특별한 종류의 객체
  • 배열 arr의 요소를 arr[0]처럼 대괄호를 사용해 접근하는 방식은 객체 문법에서 왔음
  • 다만 배열은 키가 숫자라는 점
  • 배열은 자바스크립트의 일곱 가지 원시 자료형에 해당하지 않고, 원시 자료형이 아닌 객체형에 속하기 때문에 객체처럼 동작
  • 배열은 객체와 마찬가지로 참조를 통해 복사됨
let fruits = ["바나나"]
let arr = fruits; // 참조를 복사함(두 변수가 같은 객체를 참조)

alert( arr === fruits ); // true
arr.push("배"); // 참조를 이용해 배열을 수정합니다.
alert( fruits ); // 바나나,배 - 요소가 두 개가 되었습니다.

배열 순회

for 문

let arr = ["사과", "오렌지", "배"];

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

for...of

let fruits = ["사과", "오렌지", "자두"];

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

Tip
for..in도 동일하게 사용가능하지만 객체에 특화되어있어 프로퍼티도 순회대상에 포함되므로 배열에서는 권장하지 않음

다차원 배열

  • 배열 역시 배열의 요소가 될 수 있음
  • 다차원 배열은 행렬을 저장하는 용도로 쓰임
let matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
];

alert( matrix[1][1] ); // 5, 중심에 있는 요소

배열의 내장 메소드

push/pop

  • push: 배열 끝에 요소를 추가
  • pop: 배열 끝 요소를 제거하고, 제거한 요소를 반환
let fruits = ["사과", "오렌지"];
fruits.push("배");
alert( fruits.pop() ); // 배열에서 "배"를 제거하고 제거된 요소를 얼럿창에 띄웁니다.

unshift/shift

  • unshift: 배열 앞에 요소를 추가
  • shift: 배열 앞 요소를 제거하고, 제거한 요소를 반환
let fruits = ["오렌지", "배"];
fruits.unshift('사과');
alert( fruits.shift() ); // 배열에서 "사과"를 제거하고 제거된 요소를 얼럿창에 띄웁니다.

성능

push와 pop은 빠르지만 shift와 unshift는 느림

<shift 연산 동작 방식>
1. 인덱스가 0인 요소를 제거합니다.
2. 모든 요소를 왼쪽으로 이동시킵니다. 이때 인덱스 1은 0, 2는 1로 변합니다.
3. length 프로퍼티 값을 갱신합니다.

그런데 배열에 요소가 많으면 요소가 이동하는 데 걸리는 시간이 길고 메모리 관련 연산도 많아짐!

toString

요소를 쉼표로 구분한 문자열이 반환됨

let arr = [1, 2, 3];

alert( arr ); // 1,2,3
alert( String(arr) === '1,2,3' ); // true

splice

요소 추가, 삭제, 교체가 모두 가능

arr.splice(index[, deleteCount, elem1, ..., elemN])

교체

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

// 처음(0) 세 개(3)의 요소를 지우고, 이 자리를 다른 요소로 대체합니다.
arr.splice(0, 3, "Let's", "dance");
alert( arr ) // now ["Let's", "dance", "right", "now"]

삭제

  • 삭제된 요소로 구성된 배열을 반환
let arr = ["I", "study", "JavaScript", "right", "now"];

// 처음 두 개의 요소를 삭제함
let removed = arr.splice(0, 2);

alert( removed ); // "I", "study" <-- 삭제된 요소로 구성된 배열

추가

  • deleteCount를 0으로 설정하면 요소를 제거하지 않으면서 새로운 요소를 추가
let arr = ["I", "study", "JavaScript"];

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

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

음수 인덱스

  • 배열 관련 메서드엔 음수 인덱스를 사용할 수 있음
  • 이때 마이너스 부호 앞의 숫자는 배열 끝에서부터 센 요소 위치를 나타냄
let arr = [1, 2, 5];

// 인덱스 -1부터 (배열 끝에서부터 첫 번째 요소)
// 0개의 요소를 삭제하고
// 3과 4를 추가합니다.
arr.splice(-1, 0, 3, 4);

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

slice

"start" 인덱스부터 ("end"를 제외한) "end"인덱스까지의 요소를 복사한 새로운 배열을 반환

arr.slice([start], [end])
let arr = ["t", "e", "s", "t"];

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

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

concat

기존 배열의 요소를 사용해 새로운 배열을 만들거나 기존 배열에 요소를 추가하고자 할 때 사용

arr.concat(arg1, arg2...)
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

forEach

주어진 함수를 배열 요소 각각에 대해 실행할 수 있게 해줌

arr.forEach(function(item, index, array) {
  // 요소에 무언가를 할 수 있습니다.
});

배열 탐색

indexOf&lastIndexOf&includes

indexOf

arr.indexOf(item, from)

  • 인덱스 from부터 시작해 item(요소)을 찾음
  • 요소를 발견하면 해당 요소의 인덱스를 반환
  • 발견하지 못했으면 -1을 반환

lastIndexOf

arr.lastIndexOf(item, from)

  • 위 메서드와 동일한 기능
  • 검색을 끝에서부터 시작한다는 점만 다름

includes

arr.includes(item, from)

  • 인덱스 from부터 시작해 item이 있는지를 검색
  • 해당하는 요소를 발견하면 true를 반환

find&findIndex

find

배열 내에서 특정 조건에 부합하는 객체 찾을때 사용

  • 함수가 참을 반환하면 탐색은 중단되고 해당 요소가 반환
  • 원하는 요소를 찾지 못했으면 undefined가 반환
let result = arr.find(function(item, index, array) {
  // true가 반환되면 반복이 멈추고 해당 요소를 반환합니다.
  // 조건에 해당하는 요소가 없으면 undefined를 반환합니다.
});
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

findIndex

  • find와 동일한 일을 하나, 조건에 맞는 요소를 반환하는 대신 해당 요소의 인덱스를 반환
  • 조건에 맞는 요소가 없으면 -1이 반환

filter

특정 조건을 충족하는 여러 요소 반환

let results = arr.filter(function(item, index, array) {
  // 조건을 충족하는 요소는 results에 순차적으로 더해집니다.
  // 조건을 충족하는 요소가 하나도 없으면 빈 배열이 반환됩니다.
});
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

배열 변형

map

배열 요소 전체를 대상으로 함수를 호출하고, 함수 호출 결과를 배열로 반환

  • 유용성과 사용 빈도가 아주 높은 메서드 중 하나
let result = arr.map(function(item, index, array) {
  // 요소 대신 새로운 값을 반환합니다.
});
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length);
alert(lengths); // 5,7,6

sort(fn)

배열의 요소를 정렬하여 배열 자체가 변경되어 재정렬된 배열 반환

  • 요소는 문자열로 취급되어 사전순으로 재정렬됨
let arr = [ 1, 2, 15 ];
// arr 내부가 재 정렬됩니다.
arr.sort();
alert( arr );  // 1, 15, 2
  • 새로운 정렬기준을 만드려면 새로운 함수를 넘겨줘야함
let arr = [ 1, 2, 15 ];
arr.sort((a, b) => a - b); // 오름차순
alert(arr);  // 1, 2, 15
  • 문자열엔 localeCompare 사용
let countries = ['Österreich', 'Andorra', 'Vietnam'];
alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (제대로 정렬이 되지 않았습니다.)
alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (제대로 정렬되었네요!)

reverse

배열의 요소를 역순으로 정렬시키고 재정렬된 배열 반환

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

split

구분자(delimiter)를 기준으로 문자열을 쪼개고 배열로 만들어 반환

  • 인자: 구분자, 배열의 길이
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2);
alert(arr); // Bilbo, Gandalf

let str = "test";
alert( str.split('') ); // t,e,s,t

join

인자를 배열 요소 사이사이에 넣고 모두 합친 후 하나의 문자열 반환

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

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

alert( str ); // Bilbo;Gandalf;Nazgul

reduce&reduceRight

reduce

배열을 기반으로 값 하나를 도출할 때 사용

let value = arr.reduce(function(accumulator, item, index, array) {
  // ...
}, [initial]);
  • 초깃값이 없으면 reduce는 배열의 첫 번째 요소를 초깃값으로 사용하고 두 번째 요소부터 함수 호출
let arr = [1, 2, 3, 4, 5];

// reduce에서 초깃값을 제거함(0이 없음)
let result = arr.reduce((sum, current) => sum + current);

alert( result ); // 15

reduceRight

reduce와 동일한 기능을 하지만 배열의 오른쪽부터 연산을 수행

isArray

배열인지 아닌지를 감별
배열이라면 true를, 배열이 아니라면 false를 반환

thisArg

라는 것도 있는데 잘안쓰므로 그냥 뭔지만 보자

  • thisArg는 func의 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);
// users.filter(user => army.canJoin(user)) // 동일한 코드

alert(soldiers.length); // 2
alert(soldiers[0].age); // 20
alert(soldiers[1].age); // 23

Reference

🔗 모던 JavaScript 튜토리얼

profile
공부한 내용은 바로바로 기록하자!

0개의 댓글