오늘은... 자꾸만 헷갈려서 맨날 MDN문서를 뒤져보고 다니는 Array에 사용되는 함수들을 몇 개 다시 연습해보기로
헷갈릴 때 찾아볼 용도로 적는 거라 진짜 대~~~충 적었음
array의 설명 출처는 mdn을 기반으로 작성합니다(https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array)
내가 가끔 까먹고 헷갈려하는 것들 몇 개 추려보자면
concat()
every()
filter()
map()
reduce()
slice() vs splice()
sort()
vs로 한건 결이 비슷한 함수들이라 데려와봤다.
기존 배열을 합쳐 새 배열을 만드는 함수
기존 배열은 변경되지 않으며, 새로운 배열을 반환한다
//두 개의 배열
let a = [1,2,3,4,5];
let b = [6,7,8];
let c = a.concat(b);
console.log(a); //[1,2,3,4,5] 변경x
console.log(b); //[6,7,8] 변경x
console.log(c); //[1,2,3,4,5,6,7,8]
배열을 합쳐준다고 생각하자!
대신 기존 배열이 변경되지 않고 새 배열이 반환되니까, 필요하다면 다른 변수에 이 반환된 배열을 담아서 쓸 수 있다.
concat()은 두 배열만 합칠 수 있는 게 아니다. 두 개 이상도 가능!
let a = [1,2,3,4,5];
let b = [6,7,8];
let c = ['a','b','c'];
let d = a.concat(b,c);
console.log(d) //[1,2,3,4,5,6,7,8,'a','b','c']
만약 concat()에 인자를 넣지 않는다면?
기존 배열을 얕은 복사해서 반환한다.
즉 복사된 배열 내 값을 변경해도 기존 배열은 멀쩡할 거라는 것
let a =[1,2,3];
let b = a.concat(); //b = [1,2,3]
b.push(4); //b = [1,2,3,4]
//a = [1,2,3] 변경x
얕은 복사가 되었기 때문에,
b에 어떤 값을 넣어도, 혹은 값을 변경해도 a는 멀쩡하다는 것이 보인다.
배열 내 모든 요소가 주어진 함수를 모두 통과하는지 알아낸다
반환값은 boolean!
every()의 괄호 안에는 함수가 들어간다
every니까 말 그대로 배열 내 값들을 "모두" 확인해야지
let a = [1,2,3,4,5];
a.every(function(element,index,array){
return element > 0; //true 반환
})
배열 내 모든 값이 0보다 크기 때문에 true를 반환합니다!
만약 모든 값들을 충족시키지 못하는 조건(ex: 0보다 작다)을 쓰면 false값이 뜹니다.
(저렇게 함수로 쓸 거라면 return을 꼬옥...써주자 까먹고 그냥 쓰면 뭐든 false값이 뜬다.)
위 처럼 함수를 써도 되고, 화살표 함수로 줄이는 것도 가능
let a = [1,2,3,4,5];
a.every( (element)=>{element>0} )
짧은 코드라서 더욱 간단해졌다.
주어진 함수를 통과한 값들만 모아서 새 배열을 반환한다
반환값이 새로운 배열
주어진 함수를 요소마다 체크한다는 점에선 every()와 비슷하니 잘 알아두기
필터 함수는 새로운 배열 반환
필터 함수는 새로운 배열 반환!!
간단한 예시로 보면
let a = [1,2,3,4,5]
let b = a.filter(function(element){
return element > 3;
})
console.log(b) //[4,5]
아! 맞아
filter의 콜백함수 첫 번째 인자는 배열의 요소, 두 번째 인자는 인덱스, 세 번재 인자는 호출된 배열 자체가 된다
(보통 다른 콜백 함수들도 이렇게 인자를 가지고 있더라)
첫 번째 인자인 element들이 3을 넘는다면 그 녀석들만 뽑아서 배열이 생성되고, b에 담겨지는 것!
배열 내 요소들이 주어진 함수를 거친 결과 나온 값들을 모아서 새로운 배열로 반환한다.
filter()와 비슷하다는 점 주의!
둘 다새 배열을 반환한다는 점은 비슷하지만, filter()는 통과되어 걸러진 녀석들을 요소로 잡고
map()은 결과 값들이 요소로 잡힌다는 점
filter는 걸러진(filtered) 녀석들이 등장하는 거고,
map은 모든 요소들이 재탄생(?)되어 등장한다
명심하자
filter는 걸러진 놈들!
map은 재탄생하는 놈들!
let a = [1,2,3,4,5];
let b = a.map(function(element){
return element * 2;
})
console.log(b); //[2,4,6,8,10]
주어진 함수는 각 요소들을 2배 해주는 함수.
배열의 각 요소들이 2배 당하고 나면 각각 2,4,6,8,10 이 된다.
새 배열이 반환된다고 했으니, 이 녀석들을 배열에 넣어주면 [2,4,6,8,10]이 되는 것이다.
주어진 함수(reducer라고 한다)에 배열의 각 요소들이 들어가 함수를 실행하고, 하나의 값으로 반환된다.
누적된 계산의 값이 최종 반환되는 것!
리듀서 함수에는 네 개의 인자가 들어갈 수 있다
[배열].reduce(function(acc,cur,idx,src){
// ...
})
acc(누산기): 함수를 거쳐서 나온 반환 값
cur(현재 값): 현재 요소 값
idx(현재 인덱스): 현재 요소를 가리키는 인덱스
src(원본 배열)
리듀서 함수는 배열의 각 요소마다 함수를 실행한다(forEach처럼).
한 번 함수를 실행할 때마다 나오는 결과값을 acc에 저장하고, 다음 요소가 있다면 다시 함수를 돌린다.
글로 쓰니까 말이 이상하네
let a = [1,2,3,4,5];
a.reduce(function(acc,cur,idx,src){
return acc + cur; // 15
})
처음 시작할 때 acc에는 배열의 첫 요소가 들어간다. 위 코드를 본다면 1이 들어간다.
그렇다면 cur에는 다음 요소인 2가 들어가고.
1+2를 리턴하면 3이 되니까,
다음 acc에는 누적값인 3이 들어가고,
cur은 3이 들어가는 것.
💡 짚고 넘어가야 할 점
reduce()함수의 매개변수를 더 자세히 보자
기본 형태는
arr.reduce(callback [, initialValue] )
콜백함수 옆에 있는 매개변수가 있냐 없냐에 따라 결과값이 달라진다.
initialValue는 콜백함수를 처음 호출할 때, 첫번째 인수인 acc에 들어갈 초기값을 정해준다!
위 코드에서는 initialValue값을 정해주지 않았기 때문에 초기값으로 배열의 첫 번째 요소가 acc에 들어갔지만,
값을 세팅하면 initialValue가 acc로 들어갈 것이다.
짧은 예시만 하나 쓰고 다음으로 넘어가본다.
위랑 같은 코드지만 initialValue값만 지정해준 코드
let a = [1,2,3,4,5];
a.reduce(function(acc,cur,idx,src){
return acc + cur; // 20
},5)
//초기값에 5가 들어갔으므로
// 5+1 = 6
// 6+2 = 8
// 8+3 = 11
// 11+4 = 15
// 15+5 = 20 이런순서로 진행된다
개념은 알면서도 사소한 차이 때문에 꼭 검색했다가 적용하는 이 두 함수...
- slice()는 원본 배열은 변하지 않은 채, 새로운 복사본 배열을 반환한다. 시작점 인덱스부터, 끝나는 인덱스 전까지 배열을 복사한다.
- splice()는 기존 배열의 요소를 삭제, 혹은 추가한다. 원본 배열이 바뀐다는 점.
slice()함수의 형태는
arr.slice([begin[,end]])
begin을 포함한 값부터 시작해서 end전(!!)까지 배열을 복사한다.
명심하자. end인덱스 전까지 복사다.
begin 값과 end값은 둘 다 생략이 가능하다. 둘 다 생략될 경우 기존 배열을 그대로 복사해서 새 배열을 뱉는다. 게다가 얕은 복사가 되기 때문에 원본 배열이 변경될 일을 걱정하지 말자.
간단한 예시 또 가져오기
let a = [1,2,3,4,5];
let b = a.slice(1,4);
console.log(b); //[2,3,4]
첫 인덱스가 1이니 배열의 요소는 2부터 시작.
두번째 인덱스가 4이기 때문에 그 전!!인덱스의 값인 4까지가 복사되는 것이다.
splice()함수의 형태는
arr.splice(start[,deleteCnt[,item1[,item2[, ...]]]])
기니까 복잡해보이네...
let arr1 = ['a','b','c','d','e'];
arr1.splice(1,3);
console.log(arr1); //['a','e']
//---------------------------------//
let arr2 = ['hi','name','KIM'];
arr2.splice(1,0,'my');
console.log(arr2); //['hi','my','name','KIM']
배열 arr1의 경우
시작인덱스 1부터 시작하고 잘라낼 갯수는 3개다. 그렇다면 arr1[1]인 'b'부터 시작해서 3개를 잘라내므로, 'a'와 'e'만이 배열에 남게된다.
배열 arr2의 경우
시작인덱스 1부터 0개의 요소를 잘라낸다. 즉 잘라내는 값은 없다. 대신 뒤에 추가할 요소로 'my'를 넣어줬다.
즉 인덱스1 위치에 'my'라는 요소를 추가하겠다는 뜻이 되므로, 배열은 ['hi','my','name','KIM']으로 바뀐다.
배열을 정렬한 후, 정렬된 배열을 반환. 복사본이 생기는 것이 아닌 원본 배열의 정렬이다.
일단 그냥 사용해본다면
let num = [1,2,1000,5,90];
num.sort();
console.log(num); //[1,1000,2,5,90];
보통의 상식으로는 저딴 순서가 아니다. 함수를 사용하면 유니코드 순서에 따라 정렬되기 때문에(문자열로 변환), 2보다 1000이 앞서게 된다.
이런 정렬을 원하지 않는다면? 비교해주는 함수를 sort()안에 넣어줘야 한다.
let num = [1,2,1000,5,90];
num.sort(function(a,b){
if(a>b) return 1;
else if(a<b) return -1;
else return 0;
});
a,b는 비교되는 요소.
a가 더 크다면, a가 b보다 큰 인덱스가 된다.
a가 더 작다면, a는 b보다 작은 인덱스가 된다.
a와 b가 동일하다면 서로 변경되지 않는다.
위를 더 간단하게 축약해서
num.sort(function(a,b){
return a-b;
})
이렇게도 바꿀 수 있다. (a-b값을 0과 비교해서 어떤지에 따라 정렬되는 듯)
진짜 단순하게 정리한거지만, 그래도 나름 복기는 되는 것 같다.