DevYoon
[JS] 배열과 포인터 본문
배열
Contents
1️⃣ 자바스크립트의 배열은 자료구조의 배열과 같나요?
2️⃣ 배열의 메서드는 어떤 종류가 있나요?
3️⃣ 고차함수에 대해서 아나요?
4️⃣ forEach 메서드와 map 메서드의 차이점에 대해 알고 있나요?
1️⃣ 자바스크립트의 배열 == 자료구조의 배열?
자료구조의 배열
- 동일한 크기의 메모리 공간이
- 빈틈없이 연속적으로 나열된 자료구조
➡️ 밀집 배열(Dense Array)
장점
단 한 번의 연산으로 임의의 요소에 접근 가능 ➡️ 임의 접근(random access)
시간복잡도 : O(1)
ex) 메모리 주소가 1000에서 시작하고 각 요소의 크기가 8byte인 배열이라면
인덱스가 0인 요소의 메모리 주소는 ➡️ 1000 + 0*8 = 1000
인덱스가 1인 요소의 메모리 주소는 ➡️ 1000 + 1*8 = 1008
단점
정렬되지 않은 배열에서 특정한 값 탐색 ➡️ 모든 배열 요소를 차례대로 탐색 (선형 탐색, Linear Search) ➡️ 시간복잡도 O(n)
➡️ 배열 [1, 5, 3, 9]가 있다고 가정했을 때, 3을 찾으려면 반복문을 통해 순회해야 함
배열에 요소를 삽입 및 삭제할 경우 배열을 연속적으로 유지하기 위해 요소를 이동시켜야 함
➡️ 배열 [1, 5, 3, 9] 중 5를 삭제할 경우 3이 인덱스 1, 9가 인덱스 2의 자리로 이동해야 함
자바스크립트의 배열
- 각각의 메모리 공간은 동일한 크기를 가지지 않아도 되며
- 연속적으로 이어져 있지 않을 수도 있음
➡️ 희소 배열(Sparse Array)
➡️ 자바스크립트의 배열은 일반적인 배열의 동작을 흉내낸 특수한 객체
console.log(Object.getOwnPropertyDescriptors([1, 2, 3]));
/*
{
'0': { value: 1, writable: true, enumerable: true, configurable: true },
'1': { value: 2, writable: true, enumerable: true, configurable: true },
'2': { value: 3, writable: true, enumerable: true, configurable: true },
length: { value: 3, writable: true, enumerable: false, configurable: false }
}
*/
➡️ 요소를 프로퍼티, 인덱스를 프로퍼티 값으로 가지고, length 프로퍼티를 가지는 객체
장점
- 특정 요소를 탐색하거나 요소를 삽입 및 삭제하는 경우, 자료구조의 배열보다 빠름
단점
- 인덱스로 배열 요소에 접근하는 경우, 자료구조의 배열보다 느림
2️⃣ 배열의 메서드 종류
isArray()
- 주어진 인수가 배열인지 아닌지 확인
- isArray(arg) 에서 arg가 배열이면 true, 아니면 false 반환
from()
- ES6에서 새롭게 도입
- 특정 객체를 변환하여 새로운 배열 생성
- 유사 배열 객체 : length 프로퍼티와 인덱스된 요소를 가지고 있는 객체
- 이터러블 객체 : 해당 요소를 개별적으로 선택할 수 있는 객체 (Map, Set, 문자열 등)
// 문자열은 이터러블이다.
const arr1 = Array.from('Hello');
console.log(arr1); // [ 'H', 'e', 'l', 'l', 'o' ]
// 유사 배열 객체를 새로운 배열을 변환하여 반환한다.
const arr2 = Array.from({ length: 2, 0: 'a', 1: 'b' });
console.log(arr2); // [ 'a', 'b' ]
// Array.from의 두번째 매개변수에게 배열의 모든 요소에 대해 호출할 함수를 전달할 수 있다.
// 이 함수는 첫번째 매개변수에게 전달된 인수로 생성된 배열의 모든 요소를 인수로 전달받아 호출된다.
const arr3 = Array.from({ length: 5 }, function (v, i) { return i; });
console.log(arr3); // [ 0, 1, 2, 3, 4 ]
of()
- ES6에서 새롭게 도입
- 전달된 인수를 요소로 갖는 배열을 생성
// 전달된 인수가 1개이고 숫자이더라도 인수를 요소로 갖는 배열을 생성한다.
const arr1 = Array.of(1);
console.log(arr1); // // [1]
const arr2 = Array.of(1, 2, 3);
console.log(arr2); // [1, 2, 3]
fill()
- 배열의 시작 인덱스부터 끝 인덱스 이전까지 하나의 값으로 채워주는 메서드
- 원본 배열 직접 변경, 변경한 배열을 리턴해줌
- fill(value, start, end)
- value : 배열 채울 값
- start : 시작인덱스, 기본값 0
- end : 끝 인덱스, 기본값 arr.length
// 길이가 6이고 배열의 원소가 모두 0인 배열을 만들기
// 리터럴 방법
const zeroArray = [0, 0, 0, 0, 0, 0];
// fill()메소드 방법
const zeroArray2 = Array(6).fill(0);
console.log(nullArray); // [0, 0, 0, 0, 0, 0]
[1, 2, 3].fill(4) // [4, 4, 4] 모두 4로 채룸
[1, 2, 3].fill(4, 1) // [1, 4, 4] 1번째 인덱스 부터 쭉 4로 채움
[1, 2, 3].fill(4, 1, 2) // [1, 4, 3] 1번째에서 2번째 인덱스 전까지 4로 채움
// fill ()을 사용하여 모두 1의 행렬(2차원 배열) 만들기
const arr = new Array(3);
for (let i=0; i<arr.length; i++) {
arr[i] = new Array(4).fill(1); // 크기가 4이고 1로 채워진 배열 생성
}
console.log(arr[0][0]); // 1
console.log(arr[1][0]); // 1
console.log(arr[2][0]); // 1
indexOf()
- 원본 배열에서 인수로 전달된 요소를 검색하여 인덱스 반환
- 중복되는 요소 있는 경우 첫번째 인덱스 반환
- 해당 요소 없는 경우 -1 반환
- indexOf(searchElement, fromIndex)
- searchElement : 검색할 요소
- fromIndex : 검색 시작할 요소, 생략 시 처음부터 검색
const foods = ['apple', 'banana', 'orange'];
// foods 배열에 'orange' 요소가 존재하는지 확인
if (foods.indexOf('orange') === -1) { // == if (!foods.includes('orange')) { }
foods.push('orange');
}
console.log(foods); // ["apple", "banana", "orange"]
concat()
- 인수로 전달된 값들(배열 또는 값)을 원본 배열의 마지막 요소로 추가한 새로운 배열을 반환
- 원본 배열 변경되지 않음
const arr1 = [1, 2];
const arr2 = [3, 4];
// 배열 arr2를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열을 반환
// 인수로 전달한 값이 배열인 경우, 배열을 해체하여 새로운 배열의 요소로 추가한다.
let result = arr1.concat(arr2);
console.log(result); // [1, 2, 3, 4]
// 숫자를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열을 반환
result = arr1.concat(3);
console.log(result); // [1, 2, 3]
// 배열 arr2와 숫자를 원본 배열 arr1의 마지막 요소로 추가한 새로운 배열을 반환
result = arr1.concat(arr2, 5);
console.log(result); // [1, 2, 3, 4, 5]
// 원본 배열은 변경되지 않는다.
console.log(arr1); // [1, 2]
push()
- 인수로 전달받은 모든 값을 원본 배열의 마지막 요소로 추가
- 변경된 length 값 반환
const arr1 = [1, 2];
// push 메소드는 원본 배열을 직접 변경한다.
arr1.push(3, 4);
console.log(arr1); // [1, 2, 3, 4]
const arr2 = [1, 2];
// concat 메소드는 원본 배열을 변경하지 않고 새로운 배열을 반환한다.
const result = arr2.concat(3, 4);
console.log(result); // [1, 2, 3, 4]
const arr1 = [1, 2];
// 인수로 전달받은 배열을 그대로 원본 배열의 마지막 요소로 추가한다
arr1.push([3, 4]);
console.log(arr1); // [1, 2, [3, 4]]
const arr2 = [1, 2];
// 인수로 전달받은 배열을 해체하여 새로운 배열의 마지막 요소로 추가한다
const result = arr2.concat([3, 4]);
console.log(result); // [1, 2, 3, 4]
pop()
- 원본 배열에서 마지막 요소를 제거하고 제거한 요소를 반환
- 원본 배열이 빈 배열일 경우 undefined를 반환
- 원본 배열을 직접 변경
const a = ['a', 'b', 'c'];
const c = a.pop();
// 원본 배열이 변경된다.
console.log(a); // a --> ['a', 'b']
console.log(c); // c --> 'c'
shift()
- 배열에서 첫 요소를 제거하고, 제거한 요소를 반환
- 빈 배열일 경우 undefined를 반환
- 대상 배열을 직접 변경
const arr = [];
arr.push(1); // [1]
arr.push(2); // [1, 2]
arr.push(3); // [1, 2, 3]
arr.shift(); // [2, 3]
arr.shift(); // [3]
arr.shift(); // []
unshift()
- 요소를 배열의 첫 인덱스로 삽입
cost arr = [1, 2, 3];
arr.shift();
console.log(arr) // [2, 3]
arr.unshift(4);
console.log(arr) // [4, 2, 3]
join()
- 배열을 문자열로 변환
- 구분자 넣지 않으면 기본값으로 콤마(,)가 포함되어 합쳐짐
const arr = ['h', 'i']
let res;
res = arr.join(); // 'h,i'
res = arr.join(' '); // 'h i'
split()
- 문자열을 배열로 변환
- 구분자를 넣지 않으면 문자열이 배열의 아이템 1개로 들어감
const arr = 'h, i';
let toArr;
toArr = arr.split(); // ['h,i']
toArr = arr.split(','); // ['h', 'i']
reverse()
- 배열의 순서를 뒤집음
arr = [1, 2, 3];
arr.reverse(); // [3, 2, 1]
splice()
- 인덱스로 배열의 아이템을 삭제 및 추가
- arr.splice(인덱스, 삭제할 개수, 추가할 아이템...);
const arr = [1, 2, 3];
arr.splice(1, 1) // [1, 3]
arr.splice(1, 1, 5) // [1, 5, 3]
slice()
- 배열의 특정한 부분을 리턴
- arr.slice(시작인덱스, 끝인덱스)
- 끝 인덱스의 앞 부분까지만 포함
const arr = [1, 2, 3, 4, 5]
arr.slice(1, 4) // [2, 3, 4]
3️⃣ 배열 고차함수
고차함수 : 함수를 파라미터로 전달받거나 연산의 결과로 반환해주는 메서드
find()
주어진 배열을 순회하면서 콜백함수 실행의 반환값이 true에 해당하는 첫번째 요소를 반환
find((element, index, array) => {...}, thisArg)
- element : 현재 배열요소값
- index : 배열 인덱스
- array : 참조한 배열
- thisArg : 콜백함수에서 this로 사용할 값
찾은 요소의 타입을 return, 없으면 undefinded를 return
const numberArr = [1, 3, 3, 5, 7];
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.find(item => {
return item.age === 20 // 해당조건에 부합하면 item값 반환
}); // {name: "Harry", age: 20}
console.log(numberArr.find(item => item === 3)); // 3
console.log(numberArr.filter(item => item === 3)); // [3, 3]
findIndex()
- find()의 리턴값이 인덱스인 버전
- findIndex((element, index, array) => {...}, thisArg)
- element : 현재 배열요소값
- index : 배열 인덱스
- array : 참조한 배열
- thisArg : 콜백함수에서 this로 사용할 값
- 요소가 테스트를 통과하면 배열의 인덱스 / 그렇지 않으면 -1 return
const objectArr = [
{ name: 'Harry', age: 20 },
{ name: 'Kim', age: 30 },
{ name: 'Steve', age: 40 }
];
console.log(objectArr.findIndex(item => {
return item.age === 20 // 해당조건에 부합하면 item의 인덱스를 반환
}); // 0
console.log(objectArr.findIndex(item => item.name === 'Kim')); // 1
filter()
- 주어진 배열을 순회하면서 콜백 함수의 반환값이 true에 해당하는 요소로만 구성된 새로운 배열을 생성하여 반환
- filter( (element, index, array) => {......}, thisArg)
- element : 현재 배열요소값
- index : 배열 인덱스
- array : 참조한 배열
- thisArg : 콜백함수에서 this로 사용할 값
- 테스트를 통과한 요소로 이루어진 새로운 배열 / 어떤 요소도 테스트를 통과하지 못했으면 빈 배열을 return
const numberArr = [1, 2, 3, 4, 5];
const numberFilterArr = numberArr.filter((item) => {
return item % 2 === 0; // 해당조건에 부합으면 item을 넣어 배열 반환
});
console.log(numberArr); // [1, 2, 3, 4, 5]
console.log(numberFilterArr); // [2, 4]
reduce()
- 이전 콜백 함수의 실행된 반환값을 전달 받은 연산의 결과값이 반환
- acc서부터 시작해서 배열값cur을 순회하며 acc+=cur을 실행
- reduce( (accumulator, currentValue, index, array) => {......}, initialValue)
- accumulator : 누산기. 순회하면서 계속 더해해서 합쳐지는 값
- currentValue : 현재 값
- index : 배열 인덱스
- array : 참조한 배열
- initialValue : 콜백 최초 호출에서 acc 누산기에 제공하는 값. 초기값을 제공하지 않으면 배열의 첫 번째 요소를 사용. 빈 배열에서 초기값 없이 호출하면 에러.
- 누적 계산의 결과값을 return
*️⃣ PLUS
reduce()함수 호출시 initialValue 값이 없는 경우
accumulator : 배열의 첫번째 값
currentValue : 배열의 두번째 값
reduce()함수 호출시 initialValue 값이 있는 경우
accumulator : initialValue가 지정한 값
currentValue : 배열의 첫번째 값
const numberArr = [1, 2, 3, 4, 5];
const sum = numberArr.reduce((previousValue, currentValue, currentIndex, thisArray) => {
console.log('Current Index: ' + currentIndex + ' / Previous Value: ' + previousValue
+ ' / Current Value: ' + currentValue);
return previousValue + currentValue; // 연산한 결과값을 누산기previousValue에 넣어 최종값을 얻는다.
}, 0);
console.log('Sum: ' + sum);
/*
Current Index: 0 / Previous Value: 0 / Current Value: 1
Current Index: 1 / Previous Value: 1 / Current Value: 2
Current Index: 2 / Previous Value: 3 / Current Value: 3
Current Index: 3 / Previous Value: 6 / Current Value: 4
Current Index: 4 / Previous Value: 10 / Current Value: 5
Sum: 15
*/
sort()
- 원 배열이 정렬됨
- sort(comperFunction)
- comperFunction : 정렬 순서를 정의하는 함수
- 생략 시 배열의 요소들이 문자열로 취급되어 유니코드 값 순서대로 정렬됨
- 따라서 숫자 정렬 시 설정해주어야 함
숫자 정렬
const arr = [2, 1, 3, 10];
arr.sort(function(a, b) {
return a - b;
}); // [1, 2, 3, 10] 오름차순
arr.sort(function(a, b) {
return b - a;
}); // [10, 3, 2, 1] 내림차순
문자 정렬
const arr = ['banana', 'b', 'boy'];
arr.sort(); // ['b', 'banana', 'boy']
arr.sort(function(a, b) {
if(a < b) return 1;
if(a > b) return -1;
if(a === b) return 0;
}); // ['boy', 'banana', 'b'] 내림차순
some()
- 배열의 요소들이 주어진 함수(조건)을 통과하는데 한개라도 통과되면 true, 다 아닐때에는 false를 출력
- 빈 배열로 함수(조건)을 통과하면 무조건 false를 출력
- some( (currentValue, index, array) => {......}, thisArg)
- currentValue : 현재 배열요소값
- index : 배열 인덱스
- array : 참조한 배열
- thisArg : 콜백함수에서 this로 사용할 값
const array = [1, 3, 5];
// checks whether an element is even
const even = (element) => element % 2 === 0;
console.log(array.some(even));
// expected output: false이다.
// 그 이유는 array의 3개의 요소 모두 2로 나눌때 나머지가 0이 아니기 때문이다.
every
- 배열의 요소들이 주어진 함수(조건)을 통과하는데 모두 통과되면 true, 한 개라도 통과하지 못하면 false를 출력
- 빈 배열로 함수(조건)을 통과시키면 무조건 true를 출력
- every( (currentValue, index, array) => {......}, thisArg)
- currentValue : 현재 배열요소값
- index : 배열 인덱스
- array : 참조한 배열
- thisArg : 콜백함수에서 this로 사용할 값
const array1 = [1, 30, 39, 29, 100, 13];
const isBelowThreshold = (currentValue) => currentValue < 40;
console.log(array1.every(isBelowThreshold));
// expected output: false이다.
// array1요소 중 100이 조건에 맞지 않기 때문이다.
forEach()
- for문을 대체하는 고차함수
- 내부에서 주어진 배열을 순회하며 연산 수행
- forEach((item, index, thisArr) => {.......})
- item : 배열요소값
- index : 배열 인덱스
- thisArr : 참조한 배열
const numberArr = [1, 2, 3, 4, 5];
let total = 0;
numberArr.forEach((item) => {
total += item;
});
console.log(total); // 15
map()
- 순회하면서 콜백함수에서의 실행결과를 리턴한 값으로 이루어진 배열을 만들어 반환
- map((currentValue, index, array) => {}, thisArg)
- currentValue : 현재 배열요소 값
- index : 배열 인덱스
- array : 참조한 배열
- thisArg : 콜백함수에서 this로 사용할 값
- 찾은 요소의 타입을 return, 없으면 undefinded를 return
const numberArr = [1, 2, 3, 4, 5];
const numberMapArr = numberArr.map((item) => {
return (item % 2 === 0) ? 'even' : 'odd'; // 연산한 결과값을 넣어 배열 반환
});
console.log(numberMapArr); // ['odd', 'even', 'odd', 'even', 'odd']
3️⃣ forEach 메서드와 map 메서드의 차이점
두 메서드 모두 배열을 순회하는 것은 동일
forEach()는 각 요소를 참조한 연산이 이루어지고
map()은 각 요소를 다른 값으로 맵핑한 새로운 배열이 반환
➡️ forEach는 for을 대체해서 사용, map()은 연산의 결과로 새로운 배열을 생성하고자 할 때 사용
*️⃣ 참고글
for와 forEach 참고글
배열 고차함수 참고글
배열 메서드 참고글
자바스크립트 배열 참고글