배열에 대해 잘 몰랐던 부분:
1. 배열에 프로퍼티를 만들 수 있다.
const arr = [];
// 배열에 요소(element) 추가
arr[0] = 1;
arr['1'] = 2;
// 프로퍼티 추가 (배열도 객체에 속하기 때문에 아래와 같이 프로퍼티를 추가할 수 있다.)
arr['foo'] = 3;
arr.bar = 4;
arr[1.1] = 5;
arr[-1] = 6;
console.log(arr) // [1, 2, foo: 3, bar: 4, 1.1: 5, -1: 6], 배열의 length 는 2 이다.
2. 배열에서 delete 연산자를 사용할 수 있다.
const arr = [1, 2, 3];
delete arr[1];
console.log(arr) // [1, empty, 3], 배열의 length 는 3이다.
2024년에 새롭게 추가된 배열 API(with, toSpliced, toReversed, toSorted) 들은 새로운 배열을 반환하기 때문에 기존에 원본배열을 복사한 뒤 작업하지 않아도 된다.
isArray : 인자로 넣은 값이 배열인지 아닌지 확인해준다. 반환 값은 boolean
- 보통 타입 가드, 타입 좁히기를 할 때 사용.
indexOf : 인자로 넣은 값이 배열의 몇 번째 위치(index)에 있는지 확인하고, 만약 배열에 없을 경우 -1 을 반환한다.
- 1차적으로 배열에서 찾고자 하는 요소가 있는지 없는지 찾아보고, 찾은 요소의 위치를 기반으로 코드를 구현할때 해당 API를 사용한다. 단순히 요소를 찾기위한 목적이라면 includes 를 사용하면 좋다.
push : 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가하고 변경된 length 값을 반환.
- 원본 배열에 영향을 준다.
pop : 원본 배열에서 마지막 요소를 요소를 제거하고 제거한 요소를 반환.
- 원본 배열에 영향을 준다.
unshift : 인수로 전달받은 모든 값을 원본 배열의 선두에 요소로 추가하고 변경된 length 값을 반환.
- 원본 배열에 영향을 준다.
shift : 원본 배열에서 첫 번째 요소를 제거하고 제거한 요소를 반환.
- 원본 배열에 영향을 준다.
concat : 인수로 전달한 값이 배열인 경우 배열을 해체하여 새로운 배열의 요소로 추가한다.
- 새로운 배열을 생성하는 API 이기 때문에 항상 새로운 변수에 할당시킨다. 새로운 배열을 생성하기 때문에 원본배열에 영향을 주지 않는다.
const arr1 = [1, 2];
const arr2 = [3, 4];
let result = arr1.concat(arr2); // [1, 2, 3, 4]
result = arr1.concat(5) // [1, 2, 5]
result = arr1.concat(arr2, 5) // [1, 2, 3, 4, 5]
// 전개 연산자 활용
result = [ ...arr1, ...arr2 // ];[1, 2, 3, 4]
splice : 원본 배열의 중간에 요소를 추가하거나 중간에 있는 요소를 제거하는 경우 해당 메서드를 사용한다. 제거한 요소를 배열에 담아 반환한다.
- 원본 배열에 영향을 준다. 그렇기 때문에 원본 배열을 복사한 뒤 복사한 배열에 해당 메서드를 사용하는 것이 일반적이다.
- 배열의 위치(index)를 기반으로 사용되기 때문에 보통 indexOf 와 같이 사용되는 경우가 많다.
[옵션] start: 제거하기 시작할 위치, deleteCount: 제거할 요소의 개수, items: 제거한 위치에 삽입할 요소)
(new) toSpliced : splice 와 기능은 같다.
- splice 와 다르게 원본 배열에 영향을 주지 않고 새로운 배열을 생성한다.
slice : 원본 배열에서 선택한 위치부터 설정한 위치 까지를 복사하여 배열로 반환한다. 원본 배열에 영향을 주지않는다.
[옵션] start: 복사를 시작할 위치, 음수일 경우 배열의 뒤쪽부터, end:복사를 종료할 위치, 해당 옵션이 없을 경우 시작 위치 부터 끝까지
[중요] splice 를 통해 복사된 복사본은 얕은 복사를 통해 생성된다.
const todos = [
{ id: 1, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 3, content: 'Javascript', completed: false }
];
const _todos = todo.slice(); // [ ...todos ] 와 같다.
console.log(todos === _todos) // false, 참조값이 다른 별개의 객체다.
console.log(todos[0] === _todos[0]) // true, 요소의 참조값이 같다. 즉, 얕은 복사가 된 것
※ 요소까지 복사하기 위해서는 JSON.stringify() 또는 structuredClone 을 사용해 복사하면 된다.
join : 배열을 문자열로 반환한다. 인수에 구분자를 설정할 수 있다.
reverse : 원본 배열의 순서를 반대로 뒤집는다. 뒤집힌 원본 배열을 반환한다.
- 원본 배열에 영향을 준다.
- (new) toReversed : 원본 배열에 영향을 주지 않고 새로운 배열을 생성해 반환한다.
fill : 인수로 전달받은 값을 배열의 처음부터 끝까지 요소로 채운다. 모든 요소를 하나의 값만으로 채울 수 밖에 없는 단점이 있다.
[옵션] value: 채우고자 하는 값, start: 채우기 시작할 위치, end: 종료 위치, 만약 해당 값이 없으면 배열의 끝까지
// 배열 채우기: fill 의 단점에 대한 극복 방안
const sequence = (length = 0) => Array.from({ length }, (_, i) => i);
console.log(sequence(3)) // [ 1, 2, 3 ];
※ 배열을 "채워야 한다" 라는 목적에 있어 위와 같이 배열 객체와, 배열 객체의 from 메서드를 사용하는 방법도 있다. 배열 변수를 만들고 for 반복문으로 배열에 push 또는 unshift 로 넣어주는 방법 보다 간단하다.
includes : 배열에 찾고자 하는 요소(string, number 와 같은 원시 데이터)가 있는지 없는지 확인해 boolean 값으로 반환한다.
[옵션] value: 찾고자하는 요소, start: 찾기 시작할 위치
// 배열의 요소가 객체 리터럴일 경우
const todos = [
{ id: 1, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 3, content: 'Javascript', completed: false }
];
const include = (array, key, value) => {
const filter = array.filter(element => element[key] === value);
return filter.length !== 0;
}
console.log(include(todos, 'id', 1)) // true
console.log(include(todos, 'id', 6)) // false
flat : 배열 안에 배열요소가 있는 경우 평탄화해주고 새로운 배열을 반환한다.
[옵션] depth: 평탄화할 깊이 값, 기본 1
[1, [2, 3, [4, 5, [6]]]].flat() // [1, 2, 3 [4, 5, [6]]]
[1, [2, 3, [4, 5, [6]]]].flat(1) // [1, 2, 3 [4, 5, [6]]]
[1, [2, 3, [4, 5, [6]]]].flat(2) // [1, 2, 3, 4, 5, [6]]
[1, [2, 3, [4, 5, [6]]]].flat(Infinity) // [1, 2, 3, 4, 5, 6]
(new) with : 특정 위치에 있는 요소를 원하는 값으로 변경하고 새로운 배열을 반환한다.
[옵션] index: 요소의 위치, value: 원하는 값
const people = ['Sallay', 'Kyle', 'John'];
const newPeople = people.with(2, 'New');
console.log(people); // ['Sallay', 'Kyle', 'John']
console.log(newPeople); // ['Sallay', 'Kyle', 'New']
sort : 정렬
- 콜백함수를 인수로 받을 수 있고, 여기서 정렬에 대한 조건식을 정의할 수 있다.
- 인수가 없이 사용할 경우, 영어의 경우 알파벳 순서로, 한글의 경우 자음 순서로 정렬된다.
- 해당 API 의 기본 정렬순서는 "유니코드 코드 포인트"의 순서를 따른다.('1' 은 U+3031, '2' 는 U+3032...)
- 해당 API 는 요소를 문자열로 변환한 후 정렬하는데 아래와 같은 결과가 나타난다.
// 주의할 점
const numbers = [40, 100, 1, 5, 2, 25, 10];
console.log(numbers.sort()); // [1, 10, 100, 2, 25, 40, 5]
/*
* '10' 의 유니코드 -> U+0031U+030
* 따라서 보통 우리가 아는 정렬을 수행하기 위해서는
* 정렬순서를 정의하는 콜백 함수를 인수로 전달해야 한다.
*/
numbers.sort((a, b) => a - b); // 오름차 정렬, [1, 2, 5, 10, 25, 40, 100]
numbers.sort((a, b) => b - a); // 내림차 정렬
// 객체 리터럴 정렬하기
const todosA = [
{ id: 1, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 3, content: 'Javascript', completed: false }
];
const todosB = [
{ id: 1, content: 'HTML', completed: false },
{ id: 2, content: 'CSS', completed: true },
{ id: 3, content: 'Javascript', completed: false }
];
// 오름차순
const ascendingCompare = (key) => {
return (a, b) => (a[key] > b[key] ? 1 : (a[key] < b[key] ? -1 : 0));
}
// 내림차순
const descendingCompare = (key) => {
return (a, b) => (a[key] < b[key] ? 1 : (a[key] > b[key] ? -1 : 0));
}
console.log(todosA.sort(ascendingCompare('id')));
console.log(todosB.sort(descendingCompare('id')));
(new) toSorted
forEach
map
filter
reduce : 자신을 호출한 배열을 모든 요소를 순회하며 인수로 전달받은 콜백함수를 반복 호출한다. 이때 콜백함수의 반환값을 다음 순회 시에 콜백함수의 첫 번째 인수로 전달하고 하나의 결과값을 만들어 반환한다.
- 초기값 설정이 꼭 필요하다.
- 아래 예제는 실무에서 정말 많이 사용하는 것 같다.
const values = [1, 2, 3, 4, 5, 6];
const fruits = ['banana', 'apple', 'orange', 'orange', 'apple'];
// 모두 더하기
const sum = values.reduce((accumulator, currentValue, index, array) => {
return (accumulator + currentValue);
}, 0);
// 평균 구하기
const average = values.reduce((accumulator, currentValue, index, { length }) => {
return (index === length -1 ? (accumulator + currentValue) / length : accumulator + currentValue);
}, 0);
// 요소의 중복 횟수 구하기
const count = fruits.reduce((acc, curr) => {
acc[curr] = (acc[curr] || 0) + 1;
return acc;
}, {});
// 중복요소 제거 - reduce
const resultA = values.reduce((acc, curr, index, array) => {
return array.indexOf(curr) === index ? [...acc, curr] : acc;
}, []);
// 중복요소 제거 - filter
const resultB = values.filter((elem, index, array) => {
return array.indexOf(elem) === index;
});
// 중복요소 찾기 - filter
const arr = [ 5, 3, 4, 2, 3, 7, 5, 6 ];
const resultC = arr.filter((elem, index, array) => {
return array.indexOf(elem) !== index;
});
// 중복요소 제거 - Set
const resultD = [ ...new Set(values) ];
some : 배열의 요소를 순회하면서 콜백함수를 호출한다. 이때 해당 API의 콜백함수의 반환값이 단 한번이라도 참이면 true, 모두 거짓이면 false 를 반환한다.
- 아래 예제 참고
// 배열의 요소 중 10 보다 큰 요소가 단 1개라도 존재하는지 확인
[5, 10, 15].some(item => item > 10); // true
// 배열의 요소 중 0보다 작은 요소가 단 1개라도 존재하는지 확인
[5, 10, 15].some(item => item < 0); // false
// 배열의 요소 중 banana 가 단 1개라도 존재하는지 확인
['apple', 'banana', 'mango'].some(item => item === 'banana'); // true
[].some(item => item > 3); // false, 빈 배열은 상상 false 이다.
/*
* 이렇게 "몇개가 존재하는지" 확인할때 filter 를 쓰고, length 로 확인하는 것보다 some 한번 쓰는게 간단한듯
*/
every : some 과 반대로 배열의 모든 요소가 조건을 충족하는지 확인하여 boolean 값을 반환한다.
find
findIndex
flatMap : flat 과 다르게 1단계만 평탄화할 수 있다.
- map 메서드와 flat 메서드를 순차적으로 실행하는 효과가 있다.
const xAxis = [1, 2, 3, 4];
const iterations = 2;
// 특정 패던의 배열이 필요할때
const patternA = xAxis.flatMap((value) => Array.from({ length: 3 }, () => value));
const patternB = Array.from({ length: iterations }, () => xAxis).flat();
console.log(patternA); // [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4];
console.log(patternB); // [1, 2, 3, 4, 1, 2, 3, 4]
const arr = ['hello', 'world'];
arr.map(x => x.split('')).flat(); // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']
arr.flatMap(x => x.split('')); // ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'l', 'd']
// 평탄화의 깊이를 조절해야할 경우 map 과 flat 을 각각 호출한다.
arr.map((str, i) => [i, [str, str.length]]).flat(2); // [0, 'hello', 5, 1, 'world', 5]
'자바스크립트' 카테고리의 다른 글
(내용무) 인스턴스의 이름 가져오기 → instance.constructor.name (0) | 2023.10.13 |
---|---|
bind 함수 구현 (0) | 2022.12.23 |
실행컨텍스트(Excution Context) (0) | 2022.11.29 |
반복문의 동기적(for), 비동기적(forEach, map) 처리 구분 (0) | 2022.09.30 |
Deep, Shallow comparison (깊은, 얕은 비교 / mutable, immutable) (0) | 2022.09.22 |
댓글