Javascript를 사용하다보면 array를 다뤄야 할 일이 많다. 일일이 알고리즘을 작성해 다룰 수도 있겠지만, 기본적으로 제공하는 함수들을 이용하면 훨씬 효율적으로, 가독성 있게 작성할 수 있다. 이번 시간에는 Javascript에 내장되어있는 array util method들에 대해 알아보자.
length
함수가 아닌 속성이다. 배열의 길이를 반환한다.
arr.length = 5 와 같이 length에 값을 직접 대입해 배열의 길이를 변경할 수 있다.
구문
arr.length
예시
length 읽기
/* length 읽기 */
const arr = [1, 2, 3];
console.log(arr.length); // 3
for(let i = 0; i < arr.length; i++) {
console.log(arr[i]); // 1, 2, 3
}
/* 실행 결과 */
3
1
2
3
length 변경하기
/* length 변경하기 */
const arr = [1, 2, 3];
arr.length = 5;
console.log(arr); // [1, 2, 3, undefined, undefined]
arr.length = 1;
console.log(arr); // [1]
/* 실행 결과 */
[ 1, 2, 3, undefined, undefined ]
[ 1 ]
at
arr.at(1) 과 같이 지정된 index에 해당하는 요소를 반환한다. arr[1] 과 같은 대괄호 표기법과의 차이점은 index 값으로 음수를 줄 수 있다는 것이다. index 값이 음수일 시, 배열의 마지막을 기준으로 요소를 반환한다. (arr.length - value)
즉, arr[arr.length - 1] === arr.at(-1) 이 성립한다.
구문
at(index)
매개변수
- index: 반환할 요소의 위치, 음수일 경우 뒤에서부터 센다.
예시
const arr = [1, 2, 3, 4, 5];
console.log(arr.at(2)); // 3
console.log(arr.at(-2)); // 4
/* 실행 결과 */
3
4
concat
배열에 또다른 배열을 이어붙여 새로운 배열을 만들고 반환한다. 기존 배열의 값은 변경되지 않는다.
number, boolean등 primitive type일 경우엔 값을 복사하지만, 배열의 요소가 객체일 경우 얕은 복사를 한다.
따라서 객체를 수정하면 새 배열과 원본 배열의 객체 모두 값이 바뀐다.
구문
concat([value1[, value2[, ...[, valueN]]]])
매개변수
- valueN: 기존 배열에 이어붙일 값 또는 다른 배열.
예시
배열 이어붙이기
/* 배열 이어붙이기 */
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
console.log(arr1.concat()); // [1, 2, 3]
console.log(arr1.concat(arr2)); // [1, 2, 3, 4, 5, 6]
console.log(arr1.concat(arr2, arr3)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
/* 실행 결과 */
[ 1, 2, 3 ]
[ 1, 2, 3, 4, 5, 6 ]
[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
값 이어붙이기
/* 값 이어붙이기 */
const arr = [1, 2, 3];
console.log(arr.concat(4, 5, 6)); // [1, 2, 3, 4, 5, 6]
/* 실행 결과 */
[ 1, 2, 3, 4, 5, 6 ]
객체 참조 복사
/* 객체 참조 복사 */
const arr1 = [
{ name: "a" },
{ name: "b" },
]
const arr2 = [
{ name: "c" },
{ name: "d" },
]
const arr3 = arr1.concat(arr2);
arr3[3].name = "changed";
console.log(arr3);
console.log(arr2);
/* 실행 결과 */
[
{ name: "a" },
{ name: "b" },
{ name: "c" },
{ name: "changed" }
]
[
{ name: "c" },
{ name: "changed" }
];
객체는 얕은 복사로 동작하기 때문에 arr3에서 수정한 객체가 arr2에 그대로 적용된것을 볼 수 있다.
copyWithin
특정 위치(target) 에 지정된 범위(start ~ end) 의 요소를 복사하여 반환한다. 원본 데이터가 수정된다.
구문
copyWithin(target[, start[, end]])
매개변수
- target: 복사된 값이 저장되기 시작할 index, 음수일 경우 뒤에서부터 센다. 만약 배열의 범위를 벗어난 값일 경우 아무것도 복사하지 않는다.
- start (optional): 복사할 범위의 시작 index, 음수일 경우 뒤에서부터 센다. default 값은 0이다.
- end (optional): 복사할 범위의 마지막 index, 음수일 경우 뒤에서부터 센다. end index 전까지만 복사된다. default 값은 arr.length이다.
예시
target만 지정하는 경우
/* target만 지정하는 경우 */
console.log([1, 2, 3, 4, 5].copyWithin(2)); // [1, 2, 1, 2, 3]
console.log([1, 2, 3, 4, 5].copyWithin(-3)); // [1, 2, 1, 2, 3]
/* 실행 결과 */
[ 1, 2, 1, 2, 3 ]
[ 1, 2, 1, 2, 3 ]
start와 end를 지정하지 않았기 때문에 객체의 처음부터 끝까지 복사한다. 길이가 5인 배열 기준 2와 -3 index는 같은 위치를 가리키기 때문에 결과가 동일한것을 볼 수 있다.
start도 지정하는 경우
/* start도 지정하는 경우 */
console.log([1, 2, 3, 4, 5].copyWithin(0, 3)); // [4, 5, 3, 4, 5]
console.log([1, 2, 3, 4, 5].copyWithin(-5, -2)); // [4, 5, 3, 4, 5]
/* 실행 결과 */
[ 4, 5, 3, 4, 5 ]
[ 4, 5, 3, 4, 5 ]
index 0을 기준으로 arr[3] ~ 끝까지 복사한다. [4, 5]가 배열의 맨 처음에 복사된것을 볼 수 있다.
start, end 모두 지정하는 경우
/* start, end 모두 지정하는 경우 */
console.log([1, 2, 3, 4, 5].copyWithin(1, 2, 4)); // [1, 3, 4, 4, 5]
console.log([1, 2, 3, 4, 5].copyWithin(-4, -3, -1)); // [1, 3, 4, 4, 5]
/* 실행 결과 */
[ 1, 3, 4, 4, 5 ]
[ 1, 3, 4, 4, 5 ]
index 1을 기준으로 arr[2] ~ arr[4] 전까지 복사한다. [3, 4]가 1번 index에 복사된것을 볼 수 있다.
fill
배열의 특정 범위를 주어진 값으로 채워 반환한다. 원본 데이터가 수정된다.
구문
fill(value[, start[, end]])
매개변수
- value: 배열을 채울 값
- start (optional): 값을 채우기 시작할 인덱스. default 값은 0이다.
- end (optional): 값을 채울 마지막 인덱스. default 값은 arr.length이다. end index 전까지만 채워진다.
예시
const arr = [10, 20, 30, 40, 50];
console.log(arr.fill(100));
console.log(arr.fill(500, 2));
console.log(arr.fill(300, 1, -1));
/* 실행 결과 */
[ 100, 100, 100, 100, 100 ]
[ 100, 100, 500, 500, 500 ]
[ 100, 300, 300, 300, 500 ]
entries
배열의 각 index에 대한 키/값 쌍을 가지는 새로운 Array Iterator 객체를 반환한다.
구문
entries()
예시
Iterator 사용
/* Iterator 사용 */
const arr = ["a", "b", "c"];
const iterator = arr.entries();
console.log(iterator.next().value);
console.log(iterator.next().value);
/* 실행 결과 */
[ 0, 'a' ]
[ 1, 'b' ]
for문 사용
/* for문 사용 */
const arr = ["a", "b", "c"];
console.log("for ... in");
for (const element in arr.entries()) {
console.log(element);
}
console.log("for ... of");
for (const element of arr.entries()) {
console.log(element);
}
/* 실행 결과 */
for ... in
for ... of
[ 0, 'a' ]
[ 1, 'b' ]
[ 2, 'c' ]
for ... in은 Object의 property를 기준으로 순회한다. 하지만 array.entries가 반환하는 Array Iterator는 기본적으로 어떤 property도 갖고있지 않기 때문에, 아무것도 출력되지 않는것을 볼 수 있다.
반면 for ... of는 iterable한 객체를 순회하기 때문에, Array Iterator가 정상적으로 동작하는것을 볼 수 있다.
Sparse Array
/* Sparse Array */
const arr = [];
arr[3] = "sparse";
arr[7] = "array";
for (const element of arr.entries()) {
console.log(element);
}
/* 실행 결과 */
[ 0, undefined ]
[ 1, undefined ]
[ 2, undefined ]
[ 3, 'sparse' ]
[ 4, undefined ]
[ 5, undefined ]
[ 6, undefined ]
[ 7, 'array' ]
Sparse Array의 경우 빈 슬롯을 건너뛰지 않고, undefined로 채워서 접근할 수 있게 해준다.
forEach
배열 안의 모든 요소에 대해 주어진 함수를 실행한다.
구문
arr.forEach(callbackFn[, thisArg])
매개변수
- callbackFn: 각 요소에 대해 실행할 함수, 3개의 매개변수를 가진다.
- value: 반복 시 현재 요소가 들어온다.
- index (optional): 반복 시 현재 인덱스가 들어온다.
- array (optional): forEach를 호출한 배열이 들어온다.
- thisArg (optional): callbackFn을 실행할 때 this로 사용될 값을 정의한다.
예시
/* Sparse Array */
const arr = [10, 20, 30, 40, 50];
let sum = 0;
arr.forEach((value) => {
sum += value;
console.log(`sum: ${sum}`);
});
arr.forEach((value, index, array) => {
console.log(`value: ${value} index: ${index} array: ${array}`);
});
console.log(`sum: ${sum}`);
/* 실행 결과 */
sum: 10
sum: 30
sum: 60
sum: 100
sum: 150
value: 10 index: 0 array: 10,20,30,40,50
value: 20 index: 1 array: 10,20,30,40,50
value: 30 index: 2 array: 10,20,30,40,50
value: 40 index: 3 array: 10,20,30,40,50
value: 50 index: 4 array: 10,20,30,40,50
sum: 150
every / some
every: 배열 안의 모든 요소가 판별 함수를 통과하는지 테스트한다. 판별 함수의 결과가 falsy할 때까지 반복하며, 모든 요소의 판별 결과값이 truthy일 경우 true를, 하나라도 falsy일 경우 false를 반환한다. 빈 값은 판별 함수를 실행하지 않고 건너뛴다. (AND 연산이라고 생각하면 편하다.)
some: 배열 안의 요소들 중 하나라도 판별 함수를 통과하는지 테스트한다. 판별 함수의 결과가 truthy할 때까지 반복하며, 하나라도 truthy일 경우 true를, 모든 요소의 판별 결과값이 falsy일 경우 false를 반환한다. 빈 값은 판별 함수를 실행하지 않고 건너뛴다. (OR 연산이라고 생각하면 편하다.)
구문
every(callbackFn[, thisArg])
some(callbackFn[, thisArg])
매개변수
- callbackFn: forEach의 callbackFn과 같다. 단, 판별 결과 (truthy / falsy)를 반환해야 한다.
- thisArg (optional): forEach의 thisArg와 같다. callbackFn을 실행할 때 this로 사용될 값을 정의한다.
예시
every, some
/* every, some */
const arr = [1, 2, "3", "4"];
console.log(arr.every((e) => e > 0));
console.log(arr.every((e) => typeof e === "number"));
console.log(arr.some((e) => typeof e === "number"));
console.log(arr.some((e) => e > 5));
/* 실행 결과 */
true
false
true
false
Sparse Array
/* Sparse Array */
const arr = [1, , 3];
console.log(arr.every((e) => typeof e === "number"));
console.log(arr.some((e) => typeof e !== "number"));
/* 실행 결과 */
true
false
find / findLast
find: 판별 함수를 만족하는 첫번째 값을 반환한다. 만약 없다면, undefined를 반환한다.
findLast (Node.js 18+): 판별 함수를 만족하는 마지막 값을 반환한다. 만약 없다면, undefined를 반환한다.
구문
find(callbackFn[, thisArg])
findLast(callbackFn[, thisArg])
매개변수
- callbackFn: forEach의 callbackFn과 같다. 단, 판별 결과 (truthy / falsy)를 반환해야 한다.
- thisArg (optional): forEach의 thisArg와 같다. callbackFn을 실행할 때 this로 사용될 값을 정의한다.
예시
const arr = [10, 20, 30, 40, 50];
console.log(arr.find((e) => e > 25));
console.log(arr.findLast((e) => e > 25));
console.log(arr.find((e) => e < 25));
console.log(arr.findLast((e) => e < 25));
/* 실행 결과 */
30
50
10
20
findIndex / findLastIndex
find는 값을 반환하는 반면, findIndex는 index를 반환한다.
findIndex: 판별 함수를 만족하는 첫번째 요소의 index를 반환한다. 만약 없다면, -1을 반환한다.
findLastIndex (Node.js 18+): 판별 함수를 만족하는 마지막 요소의 index를 반환한다. 만약 없다면, -1을 반환한다.
구문
findIndex(callbackFn[, thisArg])
findLastIndex(callbackFn[, thisArg])
매개변수
- callbackFn: forEach의 callbackFn과 같다. 단, 판별 결과 (truthy / falsy)를 반환해야 한다.
- thisArg (optional): forEach의 thisArg와 같다. callbackFn을 실행할 때 this로 사용될 값을 정의한다.
예시
const arr = [10, 20, 30, 40, 50];
console.log(arr.findIndex((e) => e > 25));
console.log(arr.findLastIndex((e) => e > 25));
console.log(arr.findIndex((e) => e < 25));
console.log(arr.findLastIndex((e) => e < 25));
/* 실행 결과 */
2
4
0
1
indexOf / lastIndexOf
indexOf: 특정 요소의 첫번째 인덱스를 반환한다. 없을 경우 -1을 반환한다. 배열의 처음에서 끝 방향으로 검색한다.
lastIndexOf: 특정 요소의 마지막 인덱스를 반환한다. 없을 경우 -1을 반환한다. 배열의 끝에서 처음 방향으로 검색한다.
구문
indexOf(element[, fromIndex])
lastIndexOf(element[, fromIndex])
매개변수
- element: 배열에서 찾을 요소
- fromIndex: 요소를 찾기 시작할 인덱스.
예시
const arr = [10, 20, 30, 20, 40, 30, 20, 20, 10];
console.log(arr.indexOf(20));
console.log(arr.lastIndexOf(20));
console.log(arr.indexOf(20, 4));
console.log(arr.lastIndexOf(20, 4));
console.log(arr.indexOf(0));
console.log(arr.lastIndexOf(0));
/* 실행 결과 */
1
7
6
3
-1
-1
map, flatMap
map: 배열의 모든 요소들을 주어진 함수에 따라 변환하여 새로운 배열을 반환한다. React에서 많이 쓰인다.
flatMap: map으로 변환된 새로운 배열에서 1차원 낮춰진 배열을 반환한다.
구문
map(callbackFn[, thisArg])
flatMap(callbackFn[, thisArg])
매개변수
- callbackFn: forEach의 callbackFn과 같다. 단, 새로운 배열에 들어갈 요소를 반환해야 한다.
- thisArg (optional): forEach의 thisArg와 같다. callbackFn을 실행할 때 this로 사용될 값을 정의한다.
예시
map
const arr1 = ["10", "20", "30", "40", "50"];
console.log(arr1);
const arr2 = arr1.map((e) => parseInt(e));
console.log(arr2);
const arr3 = arr2.map((e, index) => {
return { id: index, value: e };
});
console.log(arr3);
/* 실행 결과 */
[ '10', '20', '30', '40', '50' ]
[ 10, 20, 30, 40, 50 ]
[
{ id: 0, value: 10 },
{ id: 1, value: 20 },
{ id: 2, value: 30 },
{ id: 3, value: 40 },
{ id: 4, value: 50 }
]
React
<div className="flex flex-col items-center w-full min-h-full">
{friendList &&
friendList.map((user) => (
<FriendItem
key={user.id}
friendListItem={user}
onDeleteClick={onDeleteClick}
onDirectClick={onDirectClick}
/>
))}
</div>
flatMap
const arr = ["My", "name", "is", "DevJaewoo"];
console.log(arr.map((e) => e.split("")));
console.log(arr.flatMap((e) => e.split("")));
/* 실행 결과 */
[ [ 'M', 'y' ], [ 'n', 'a', 'm', 'e' ], [ 'i', 's' ], [ 'D', 'e', 'v', 'J', 'a', 'e', 'w', 'o', 'o' ] ]
[ 'M', 'y', 'n', 'a', 'm', 'e', 'i', 's', 'D', 'e', 'v', 'J', 'a', 'e', 'w', 'o', 'o' ]
map이 반환한 배열은 단어별로 하나의 배열에 묶여있지만, flatMap이 반환한 배열은 배열이 해체되어있는것을 볼 수 있다.
reduce / reduceRight
reduce: 배열의 시작부터 끝 방향으로 주어진 함수를 실행한다. 함수를 실행할 때, 이전 요소에서 실행했던 함수의 반환값이 주어진다.
reduceRight: reduce를 배열의 끝부터 시작 방향으로 진행한다.
구문
reduce(callbackFn[, initialValue])
매개변수
- callbackFn: 각 요소에 대해 실행할 함수, 3개의 매개변수를 가진다.
- accumulator: 이전 요소에서 함수를 실행한 결과가 들어온다.
- currentValue: 반복 현재 요소
- array (optional): forEach를 호출한 배열이 들어온다.
- thisArg (optional): callbackFn을 실행할 때 this로 사용될 값을 정의한다.
예시
const arr = [10, 20, 30];
arr.unshift(0);
arr.push(40);
console.log(arr);
arr.unshift(-300, -200, -100);
arr.push(100, 200, 300);
console.log(arr);
/* 실행 결과 */
[0, 10, 20, 30, 40]
[-300, -200, -100, 0, 10, 20, 30, 40, 100, 200, 300]
push / unshift
push: 배열의 맨 끝에 요소들을 추가하고, length를 반환한다.
unshift: 배열의 맨 앞에 요소들을 추가하고, length를 반환한다.
구문
push([value1][, value2] ... [, valueN])
unshift([value1][, value2] ... [, valueN])
매개변수
- valueN (optional): 배열에 추가될 요소. 만약 아무 요소도 전달하지 않는다면, length만 반환한다.
예시
const arr = [10, 20, 30];
arr.unshift(0);
arr.push(40);
console.log(arr);
arr.unshift(-300, -200, -100);
arr.push(100, 200, 300);
console.log(arr);
/* 실행 결과 */
[0, 10, 20, 30, 40]
[-300, -200, -100, 0, 10, 20, 30, 40, 100, 200, 300]
pop / shift
pop: 배열의 맨 끝의 요소를 제거하고, 반환한다. 만약 요소가 없었다면, undefined를 반환한다.
shift: 배열의 맨 앞의 요소를 제거하고, 반환한다. 만약 요소가 없었다면, undefined를 반환한다.
구문
pop()
push()
예시
let arr = [10, 20, 30];
for (let i = arr.length; i > 0; i--) {
console.log(arr.pop());
}
console.log(arr.pop());
arr = [10, 20, 30];
for (let i = arr.length; i > 0; i--) {
console.log(arr.shift());
}
console.log(arr.pop());
/* 실행 결과 */
30
20
10
undefined
10
20
30
undefined
slice
배열의 특정 범위의 요소를 추출하여 반환한다. 원본 배열을 수정하지 않는다.
구문
array.slice([start][, end])
매개변수
- start (optional): 추출할 범위의 시작 index, 음수일 경우 뒤에서부터 센다. 지정하지 않을 경우 배열 전체를 반환한다.
- end (optional): 추출할 범위의 마지막 index, 음수일 경우 뒤에서부터 센다. end index 전까지만 추출된다. default 값은 arr.length이다.
예시
const arr = [100, 200, 300, 400, 500];
console.log(arr.slice());
console.log(arr.slice(2));
console.log(arr.slice(-2, 5));
console.log(arr);
/* 실행 결과 */
[ 100, 200, 300, 400, 500 ]
[ 300, 400, 500 ]
[ 400, 500 ]
[ 100, 200, 300, 400, 500 ]
splice
배열의 특정 위치로부터 특정 개수의 요소를 삭제하고, 그 자리에 새로운 요소들을 추가한다. 제거된 요소들을 배열로 반환하며, 원본 배열을 수정한다.
구문
array.splice(start[, deleteCount][, item1][, item2] ... [, itemN])
매개변수
- start: 제거를 시작할 요소의 index, 음수 지정이 가능하다.
- deleteCount (optional): start로부터 제거할 요소의 개수. 생략하면 start부터 배열의 끝까지 제거한다.
- itemN (optional): 제거 이후 추가될 요소. 생략하면 splice는 요소를 제거하기만 한다.
예시
const arr = [100, 200, 300, 400, 500, 600, 700, 800];
console.log(arr.splice(5), arr);
console.log(arr.splice(-3, 2), arr);
console.log(arr.splice(1, 1, 400, 300, 200), arr);
/* 실행 결과 */
[ 600, 700, 800 ] [ 100, 200, 300, 400, 500 ]
[ 300, 400 ] [ 100, 200, 500 ]
[ 200 ] [ 100, 400, 300, 200, 500 ]
'Study > Javascript' 카테고리의 다른 글
[Javascript] 비동기를 통해 프로그램의 효율 향상시키기 (Callback, Promise, async / await) (0) | 2023.05.13 |
---|---|
[Javascript] var, let, const의 특징과 var의 문제점 (2) | 2023.03.10 |
[Javascript] Number, Number.parseInt, parseInt의 차이 (0) | 2022.09.26 |