const products = [
{name: '반팔티', price: 15000},
{name: '긴팔티', price: 20000},
{name: '핸드폰케이스', price: 15000},
{name: '후드티', price: 30000},
{name: '바지', price: 25000}
];
map()는 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 🔔새로운 배열을 반환한다.
arr.map(callback(currentValue[, index[, array]])[, thisArg])
callback : 새로운 배열 요소를 생성하는 함수 3가지 인수를 가진다.
(1) currentValue : 처리할 현재 요소
(2) index : 처리할 현재 요소의 인덱스
(3) array : map()을 호출한 배열
thisArg : callback을 실행할 떄 this로 사용되는 값
🔧 rObj {}에 obj.key를 key값으로 obj.value를 value값으로 구성해서 각각의 요소에 대해 한번씩 순서대로 불러서 새로운 배열을 반환값으로 return한다.
var kvArray = [{key:1, value:10},
{key:2, value:20},
{key:3, value: 30}];
var reformattedArray = kvArray.map(function(obj){
var rObj = {};
rObj[obj.key] = obj.value;
return rObj;
});
// reformattedArray는 [{1:10}, {2:20}, {3:30}]
// kvArray는 그대로
// [{key:1, value:10},
// {key:2, value:20},
// {key:3, value: 30}]
🔧 map의 작동 방식
// f iter를 인자로 받고 f를 a인자를 받는 함수화시켜서 결과값을 res에 담는다
const map = (f, iter) => {
let res = [];
for (const a of iter){
res.push(f(a));
}
return res;
};
let names = [];
for (const p of products){
names.push(p.name);
}
log(name);
log(map(p=>p.name, products)); // products에 있는 name들 출력
let prices = [];
for (const p of products){
names.push(p.price);
}
log(name);
log(map(p=>p.price, products)); // products에 있는 price들 출력
map함수는 iterator 프로토콜을 따르는 함수들 사용이 가능하다.
function *gen(){
yield 2;
yield 3;
yield 4;
}
log(map((a => a*a, gen());
// [4,9,16]
let m = new Map();
m.set('a',10);
m.set('b',20);
map(([k,a]=>[k,a*2]), m); // ["a",20],["b",40]
const it = m[Symbol.iterator]();
log(it.next()); // value:Array(2) ["a",10]
log(it.next()); // value:Array(2) ["b",20]
filter()는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 🔔새로운 배열로 반환한다.
arr.filter(callback(element[, index[, array]])[, thisArg])
callback : 각 요소를 시험할 함수. true 반환시 요소 유지, false 반환시 버림 3가지 매개변수를 받는다.
(1) element : 처리할 현재 요소
(2) index : 처리할 현재 요소의 인덱스
(3) array : filter()을 호출한 배열
thisArg : callback을 실행할 때 this로 사용하는 값
🔧 indexOf는 배열에서 지정된 요소를 찾을 수 있는 첫 번째 인덱스를 반환하고 존재하지 않으면 -1을 반환
const fruits = ['apple', 'banana', 'grapes', 'mango', 'orange'];
/**
* 검색 조건에 따른 배열 필터링(쿼리)
*/
const filterItems = (query) => {
return fruits.filter((el) =>
el.toLowerCase().indexOf(query.toLowerCase()) > -1
);
}
console.log(filterItems('ap')); // ['apple', 'grapes']
console.log(filterItems('an')); // ['banana', 'mango', 'orange']
🔧 filter의 작동 방식
const filter = (f, iter) =>{
let iter = [];
for (const p of iter){
if(f(a)) res.push(a);
}
}
let under20000 = [];
for (const p of products) {
if(p.price < 20000) under20000.push(p);
}
log(...under20000); // 반팔티, 핸드폰케이스
log(...filter(p=>p.price < 20000, products)); // 반팔티, 핸드폰케이스
let over20000 = [];
for (const p of products) {
if(p.price >= 20000) over20000.push(p);
}
log(...over20000); // 긴팔티, 후드티, 바지
log(...filter(p=>p.price >= 20000, products)); // 긴팔티, 후드티, 바지
reduce()는 배열의 각 요소에 대해 주어진 리듀서 함수를 실행하고 하나의 결과값을 반환한다.
arr.reduce(callback[, initialValue])
리듀서 함수는 네 개의 인자를 가진다.
1. 누산기(acc) - 누산기에 리듀서 함수의 반환 값 할당, 순회 중 유지되므로 최종 결과는 하나의 값이 된다.
2. 현재값(cur)
3. 현재 인덱스(idx)
4. 원본 배열(src)
arr.reduce(function(acc,cur,idx,src)){
return acc + cur;
}
🔧 reduce 이해하기 힘들었던 예제
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
var countedNames = names.reduce(function (allNames, name) {
if (name in allNames) {
allNames[name]++;
}
else {
allNames[name] = 1;
}
return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }
❌ 궁금했던 점
1. 왜 {} 안에 들어가 있는 걸까?
2. allNames[name]은 allNames가 배열로 만들어져있다면 순서를 내밷는게 아닌가?
✅ 해결
1. 함수 뒤에 {}는 초기값으로 name들을 쌓아두는 allName이다.
2. allNames는 배열로 안에 하나씩 집어 넣는게 아니라 {}안에 딕셔러니형식으로 하나씩 쌓인다.
따라서 allNames[name]은 value이고 name은 key이다.
allNames, name의 console.log결과값
{} Alice
{ Alice: 1 } Bob
{ Alice: 1, Bob: 1 } Tiff
{ Alice: 1, Bob: 1, Tiff: 1 } Bruce
{ Alice: 1, Bob: 1, Tiff: 1, Bruce: 1 } Alice
{ Alice: 2, Bob: 1, Tiff: 1, Bruce: 1 }
🔧 reduce의 작동 방식
const nums = [1,2,3,4,5];
let total = 0;
for (const n of nums) {
total = total + n;
}
log(total)
const reduce = (f, acc, iter) => {
// iter 값이 없다면
if(!iter){
iter = acc[Symbol.iterator](); // iterable
acc = iter.next().value; // 다음 값을 초기값으로
}
for (const a of iter){
acc = f(acc,a);
}
return acc;
}
const add = (a,b) => a + b;
log(reduce(add, 0, [1,2,3,4,5])); // 15
>> log(add(add(add(add(0,1),2),3),4),5); //15
log(reduce(add, [1,2,3,4,5])); 처럼 초기값을 두지 않는다면
log(reduce(add, 1, [2,3,4,5])); reduce가 내부적으로 값을 이와 같이 받은것처럼 동작한다.
log(reduce((total_price, product) => total_price + product.price, 0, products)); // 105000
🔧 products안에 20000미만으로 filter한 값(배열)을 map으로 추출 후 reduce로 add한 값을 반환한다..
const add = (a+b) => a + b;
log(reduce(add,
map(p=>p.price,
filter(p=>p.price < 20000, products))));
// 30000
🔧 map으로 products안에 price값들(배열)을 추출 후 20000미만으로 filter한 값들을 reduce로 add한 값을 반환한다.
위와 결과값은 같다.
const add = (a+b) => a + b;
log(reduce(add,
filter(n=>n<20000,
map(p=>p.price, products))));
// 30000