[JS] 배열의 모든 것

hahaha·2021년 9월 6일
0

JavaScript

목록 보기
13/24
post-thumbnail

배열

  • 여러 개의 값을 순차적으로 나열한 자료구조
  • 인덱스(요소의 위치), 요소(값)

일반 객체와의 차이점

(배열도 객체)

구분객체배열
구조프로퍼티 키/값인덱스/요소
값의 참조프로퍼티 키인덱스
값의 순서XO
length 프로퍼티XO
  • 배열은 반복문을 통해 접근하기 쉬운 구조

특이한 자바스크립트의 배열

일반 배열

  • 하나의 데이터 타입으로 통일(각 요소가 동일한 데이터 크기)
  • 빈틈없이 연속적으로 인접해 있음(밀접 배열)

자바스크립트의 배열

  • 일반적인 배열의 동작을 흉내 낸 특수한 객체
  • 각 요소가 동일한 메모리 공간 X, 연속적으로 이어져 있지 X(희소 배열)
  • 어떤 타입의 값이라도 배열의 요소가 될 수 있음
    - 인덱스로 접근하는 경우, 일반 배열보다는 느림
    - 특정 요소 검색, 삽입, 삭제하는 경우에는 빠름

length 프로퍼티

  • 배열의 길이 (= 요소의 개수)
  • 임의로 값 설정 가능
  • 현재 length 프로퍼티 값보다 작은 숫자를 할당할 경우, 배열의 길이 감소
  • 현재 length 프로퍼티 값보다 큰 숫자를 할당할 경우, 값은 변경되나 배열 길이는 그대로
    -> 희소 배열의 length와 실제 배열 요소 개수는 일치하지 않을 수 도 있다.
    (희소 배열을 생성하지 않도록 주의...)
const arr1 = [1, 2, 3, 4];
arr1.length = 3;
console.log(arr1);	// [1, 2, 3]

const arr2 = [1, 2, 3, 4];
arr2.length = 5;
console.log(arr2.length);	// 5
console.log(arr2);		// [1, 2, 3, 4, empty]

배열 생성

1. 배열 리터럴

const arr1 = [1, 2, 3];
const arr2 = [];	// arr2.length = 0
const arr3 = [1, , 3];	// 희소 배열

2. Array 생성자 함수

  • 전달된 인수의 개수에 따라 동작
    - 숫자 1개 -> length 프로퍼티 값이 인수인 배열
    - 0개 -> 빈 배열
    - 2개 이상 or 숫자가 아닌 경우 -> 해당 인수를 요소로 갖는 배열
const arr = new Array(10);
console.log(arr);	// [empty*10]

new Array();	// []

new Array(1, 2, 3);	// [1, 2, 3]
new Array({});	// [{}]

// new 연산자 없이도 생성 가능
Array(1, 2, 3);	// [1, 2, 3]

3. Array.of

  • 전달된 인수를 요소로 갖는 배열 생성
Array.of(1, 2, 3);	// [1, 2, 3]

4. Array.from

  • 유사 배열 객체 or 이터러블 객체를 인수로 전달받아 배열로 변환 후, 반환
Array.from({ length: 2, 0: 'a', 1: 'b' });	// ['a', 'b']

// 문자열은 이터러블이다.
Array.from('Hi');	// ['H', 'i']

배열 요소의 참조/추가/갱신/삭제

비구조화 할당

  • 배열의 각 원소에 접근하지 않고 새로운 변수명을 붙일 수 있다.
const arr = [1, 2];
const [a, b, c] = arr;
console.log(a);	// 1
console.log(b);	// 2
console.log(c);	// undefined (대응하는 원소가 없는 경우, undefined 할당)
  • 객체에도 적용 가능
const obj = {a: 1, b:2 }
const {a: newA, b} = obj;	// 새로운 변수명을 사용할 수도 있음
console.log(newA);	// 1
console.log(b);	// 2

참조

  • 대괄호([]) 표기법 사용
  • 인덱스로 접근

추가

  • 동적 추가 가능
  • 존재하지 않는 인덱스 사용 시, 새로운 요소 추가 / length 자동 갱신
  • 이미 존재하는 인덱스 사용 시, 요소값 갱신
  • 정수 이외의 값을 인덱스로 사용 시, (요소가 아닌)프로퍼티 생성 / length 영향 X
const arr = [];
arr[0] = 1;
arr['1'] = 2;
arr['foo'] = 3;
arr[1.1] = 4;

console.log(arr);		// [1, 2, foo: 3, '1.1': 4]
console.log(arr.length);	// 2

삭제

  • delete 연산자
    - length 영향 X
    - 희소 배열이 됨
  • Array.prototype.splice 메서드 사용 권장
    - length 자동 갱신
const arr = [1, 2, 3];

delete arr[1];
console.log(arr);		// [1, empty, 3]
console.log(arr.length);	// 3

const arr2 = [1, 2, 3, 4];
arr2.slice(1, 2);
console.log(arr2);		// [1, 4]
console.log(arr2.length);	// 2

메서드

결과물 반환 패턴

  1. 부수 효과 O
    : 원본 배열(배열 메서드를 호출한 배열, 배열 메서드 내부에서 this가 가리키는 객체) 직접 변경
  2. 부수 효과 X
    : 원본 배열 변경없이 새로운 배열을 생성하여 반환

isArray

  • 전달된 인수가 배열이면 true

indexOf

  • 전달된 인수를 검색하여 인덱스 반환
  • 중복되는 요소가 있을 경우, 첫 번째로 검색된 요소의 인덱스 반환
  • 요소가 존재하지 않으면 -1 반환

push

  • 전달된 인수를 원본 배열의 마지막 요소로 추가, 변경된 length 프로퍼티 값 반환
  • 원본 배열을 직접 변경
  • (부수 효과 O)
    - 스프레드 문법 사용하는 것을 권장

pop

  • 마지막 요소를 제거하고 제거한 요소 반환
  • (부수 효과 O)

unshift

  • 전달된 모든 인수를 원본 배열의 선두에 추가, 변경된 length 프로퍼티 값 반환
  • (부수 효과 O)
const arr = [1, 2];
let result = arr.unshift(3, 4);
console.log(result);	// 4
console.log(arr);	// [3, 4, 1, 2]

shift

  • 원본 배열에서 첫 번째 요소를 제거, 제거한 요소 반환
  • pop의 반대
  • (부수 효과 O)

concat

  • 전달된 인수를 원본 배열의 마지막 요소로 추가한 새로운 배열 반환
  • push/unshift, concat ... 등의 메서드를 사용하는 대신 ES6의 스프레드 문법을 일관성 있게 사용하는 것을 권장

splice

arr.slice(start, deleteCount, items);
  • 원본 배열의 start 부터 deleteCount 만큼 제거하여 items 요소들을 삽입
    • deleteCount = 0, 제거 없이 items 삽입
    • items 생략 가능
  • 제거한 요소가 배열로 반환
  • (부수 효과 O)
const arr = [1, 2, 3, 4];
const result = arr.slice(1, 2, 20, 30);
console.log(result);	// 2, 3
console.log(arr);	// [1, 20, 30, 4]

slice

arr.slice(start, end);
  • start 부터 end-1 인덱스 범위의 요소들을 복사하여 배열로 반환
    • start 음수 가능
    • end의 default = length 프로퍼티 값
    • 인수 모두 생략 시, 복사본 생성하여 반환(얕은 복사)
const arr = [1, 2, 3];
arr.slice(0, 1);	// [1]
arr.slice(-1);		// [3]
console.log(arr);	// [1, 2, 3] 원본 배열 변경 X

얕은 복사와 깊은 복사

  • 얕은 복사: 한 단계까지만 복사하는 것
  • 깊은 복사: 객체에 중첩되어 있는 객체까지 모두 복사
  • slice, 스프레드 문법, Object.assign 메서드 모두 얕은 복사 수행
  • 깊은 복사 수행 시, Lodash 라이브러리의 cloneDeep 메서드 사용하기

join

  • 원본 배열의 모든 요소를 문자열로 변환한 후, 전달된 인수(문자열 구분자)로 연결한 문자열 반환
    • 구분자 생략 가능
    • default = 콤마(,)
const arr = [1, 2, 3, 4];
arr.join();	// '1, 2, 3, 4'
arr.join(':');	// '1:2:3:4'

reverse

  • 원본 배열의 순서를 반대로 뒤집기
  • (부수 효과 O)

fill

arr.fill(value);
arr.fill(value, start, end);
  • 전달된 인수를 배열의 처음부터 끝까지 채우기
    • 두 번째 인수로 시작 인덱스 전달 가능
    • 세 번째 인수로 멈출 인덱스 전달 가능
const arr = [1, 2, 3];
arr.fill(0, 1);
console.log(arr);	// [1, 0, 0]

includes

  • 배열 내에 특정 요소가 포함되어 있는지 확인하여 true/false로 반환
    • 두 번째 인수로 시작 인덱스 전달 가능
    • 음수 전달 시, 시작 인덱스 = (length + index)
  • ES7에서 도입

flat

  • 전달된 인수 깊이 만큼 재귀적으로 배열 평탄화
    - default = 1
    • Infinity 전달 시, 중첩 배열 모두 평탄화
  • ES10에서 도입
[1, [2, [3, 4]]].flat();	// [1, 2, [3, 4]]

배열 고차 함수

고차 함수

  • 함수를 인수로 전달 받거나 함수를 반환하는 함수
  • 외부 상태의 변경이나 가변 데이터를 피하고 불변성을 지향하는 함수형 프로그래밍에 기반

함수형 프로그래밍

  • 순수 함수와 보조 함수의 조합을 통해
    조건문과 반복문을 제거하여 복잡성 해결,
    변수의 사용 억제하여 상태 변경 피하려는 프로그래밍 패러다임
  • 순수 함수를 통해 부수 효과 최대한 억제 -> 안정성 높이기

sort

  • 기본적으로 오름차순 정렬
  • (부수 효과 O)

숫자 요소로 이루어진 배열 정렬 시, 주의 필요 !

  • 기본 정렬 순서: 유니코드 코드 포인트 순서

ex. '10': U+0031U+0030 < '2': U+0032

['2', '10'].sort();	// ["10", "2"]
  • 정렬 순서를 정의하는 비교 함수 인수로 전달
  • 비교 함수의 반환 값 < 0 인 경우, 첫 번째 인수를 우선 정렬
sort((a, b) => a - b);

forEach

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 콜백 함수 호출 시, (요소 값, 인덱스, this) 인수 전달
  • 반환값은 항상 undefined
  • 배열의 모든 요소를 빠짐없이 순회, 순회 중단 불가
    - break, continue 사용 X
  • for문에 비해 성능은 떨어지지만 가독성이 좋음
  • for 문은 반복을 위한 변수 선언, 조건식, 증감식 구성으로
    함수형 프로그래밍의 취지에 맞지 않음
[1, 2, 3].forEach((item, index, arr) => {
  console.log(`요소 값: ${item}, 인덱스: ${index}, this: ${JSON.stringify(arr)}`);
});

// 요소값: 1, 인덱스: 0, this: [1, 2, 3]


// 콜백 함수 내부에서 this로 사용할 객체 전달하기
arr.forEach(function (item) {
  // 생략
}, this);

// 더 좋은 방법: 화살표 함수 사용
// 화살표 함수 내부의 this는 상위 스코프의 this를 그대로 참조

map

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 콜백 함수의 반환값들로 구성된 새로운 배열 반환
    - map 메서드를 호출한 배열과 반환한 배열은 1:1 매핑
  • 콜백 함수 호출 시, (요소 값, 인덱스, this) 인수 전달
const numbers = [1, 4, 9];

const roots = numbers.map(item => Math.sqrt(item));
console.log(roots);	// [1, 2, 3]
console.log(numbers);	// [1, 4, 9]

filter

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 콜백 함수의 반환값이 true인 요소로만 구성된 새로운 배열 반환
const numbers = [1, 2, 3, 4, 5];

const odds = numbers.filter(item => item % 2);
console.log(odds);	// [1, 3, 5]

reduce

arr.reduce((accumulator, currentValue, index, array) => {
  // 생략
}, 초기값);
  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 콜백 함수의 반환 값을 다음 순회의 콜백 함수의 첫 번째 인수로 전달
  • 하나의 결과값을 만들어 반환
  • 자신을 호출한 배열을 순회하며 하나의 결과값을 구해야 하는 경우에 사용
const vaules = [1, 2, 3, 4, 5, 6];

const avg = values.reduce((acc, cur, i, {length}) => {
  return i === length -1 ? (acc + cur) / length : acc + cur;
}, 0);

console.log(avg);	// 3.5

some

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 콜백 함수의 반환 값이 단 한 번이라도 참 이면, true 반환
[5, 10, 15].some(item => item > 10);	// true

every

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 콜백 함수의 반환 값이 모두 참 이면, true 반환

find

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 반환 값이 true인 첫 번째 요소 반환
  • ES6 에서 도입
[1, 2, 2, 3].find(item => item === 2);	// 2

// filter는 배열 반환
[1, 2, 2, 3].filter(item => item === 2);	// [2, 2]

findIndex

  • 배열의 모든 요소를 순회하며 인수로 전달받은 콜백 함수 반복 호출
  • 반환 값이 true인 첫 번째 요소의 인덱스 반환
    - 반환 값이 true인 요소가 없는 경우, -1 반환
  • ES6 에서 도입

flatMap

  • map 메서드를 통해 생성된 새로운 배열을 평탄화하기
    • map, flat 메서드를 순차적으로 실행하는 효과
    • flat 메서드에서 평탄화 깊이 지정 불가(항상 1단계)
  • ES10 에서 도입
profile
junior backend-developer 👶💻

0개의 댓글