정의에 앞서 알아두어야 할 개념들
변수에 할당 가능
다른 함수의 인자로 전달 가능
다른 함수의 결과로 리턴 가능
const square = num => num*num // function expression
function square(num) {
return num*num;
}
함수표현식은 완전히 호이스팅되지 않아 선언전에 사용할 수 없다.
따라서 코드가 절차적으로 엄격해지고, 유지보수가 편해질 수도 있다.
고차함수는 함수를 인자로 받는 함수, 함수를 리턴하는 함수를 의미하는데
커리함수는 고차함수 중 함수를 리턴하는 함수만을 의미한다
function double(num) {
return num * 2;
}
function square(num) {
return num * num;
}
function processNum(callback, num) {
return callback(num)
}
let output = processNum(double, 4);
let output2 = processNum(square, 4);
console.log(output); // -> 8
console.log(output2); // -> 16
function adder(added) {
return function (num) {
return num + added;
};
}
let output = adder(5) // output is function
console.log(output(3)) // -> 8
let outputAtOnce = adder(5)(5) // this works since return value of adder(5) is function
console.log(outputAtOnce) // -> 10
function double(num) {
return num * 2;
}
function square(num) {
return num * num;
}
// 인자로 받은 func로 process된 결과를 adder와 합한 값을 리턴한다.
function processedAdder(num, func) {
const processed = func(num);
return function (adder) {
return adder + processed;
};
}
processedAdder(5, square)(3) // -> 28
const addTwice3 = processedAdder(3, double);
addTwice3(3); // -> 9
reduce 또는 reduceRight를 활용하면 간단하게 구현할 수 있다.
reduce의 콜백함수는 인자로 (acc, val, idx, arr)를 받을 수 있다.
function square(num) {
return num * num;
}
function add5(num) {
return num + 5;
}
function mul3(num) {
return num * 3;
}
function isOdd(num) {
return num % 2 !== 0;
}
// reduceRight
function pipe(...funcs) {
// NOTE: reduce's callback args are (acc, val, idx, array) , [initial val]
return initialVal => funcs.reduce((acc, val, idx) => val(acc), initialVal)
}
output = pipe(square, add5, mul3);
// output's arg is initialVal as above declaration
console.log(output(4)); // --> 63
객체에 특정 키가 존재하는지 확인하는 방법
// Using in operator
'key' in object
// Using hasOwnProperty() method
object.hasOwnProperty('key')
리듀스 적용해서 사전식으로 객체 정리하기
let users = [
{ name: 'Tim', age: 40 },
{ name: 'Satya', age: 30 },
{ name: 'Sundar', age: 50 }
];
const makeAddressBook = (acc, elem, idx) => {
const firstChar = elem.name[0];
if (!acc.hasOwnProperty(firstChar)) {
acc[firstChar] = [];
}
acc[firstChar].push(elem);
return acc;
};
const resultObj = users.reduce(makeAddressBook, {});
console.log(resultObj);
/*
{
T: [ { name: 'Tim', age: 40 } ],
S: [ { name: 'Satya', age: 30 }, { name: 'Sundar', age: 50 } ]
}
*/
한 가지 일만 하는 함수를 작성한 뒤, 컴포지션을 통해 합성하고, 이를 조합해서 특정 작업에 활용할 수 있다. 다음과 같은 장점이 있음.
특정 작업만 하는 함수는 좀더 generic하게 활용될 수 있음.
이 향상된다.
// bad code 💩
function getAverageAgeOfMaleAtOnce(data) {
const onlyMales = data.filter(function (d) {
// data.filter는 배열의 각 요소에 인자로 전달받은 함수를 적용하고,
// 그 결과가 true인 요소만을 갖는 배열을 리턴합니다.
return d.gender === 'male';
});
const numOfMales = onlyMales.length;
const onlyMaleAges = onlyMales.map(function (d) {
// onlyMales.map는 배열의 각 요소에 인자로 전달받은 함수를 적용하고,
// 각 결과를 요소로 갖는 배열을 리턴합니다.
return d.age;
});
const sumOfAges = onlyMaleAges.reduce(function (acc, cur) {
// onlyMaleAges.reduce는 배열의 각 요소에 인자로 전달받은 함수를 적용하고,
// 각 결과를 두 번째 인자로 전달받은 초기값(0)에 누적한 결과를 리턴합니다.
return acc + cur;
}, 0);
return sumOfAges / numOfMales;
}
// good code ✅
function getOnlyMales(data) {
return data.filter(function (d) {
return d.gender === 'male';
});
}
function getOnlyAges(data) {
return data.map(function (d) {
return d.age;
});
}
function getAverage(data) {
const sum = data.reduce(function (acc, cur) {
return acc + cur;
}, 0);
return sum / data.length;
}
// 일반적인 for loop 로 pipe 패턴 구현 👋
function compose(...funcArgs) {
// compose는 여러 개의 함수를 인자로 전달받아 함수를 리턴하는 고차 함수입니다.
// compose가 리턴하는 함수(익명 함수)는 임의의 타입의 data를 입력받아,
return function (data) {
// funcArgs의 요소인 함수들을 차례대로 적용(apply)시킨 결과를 리턴합니다.
let result = data;
for (let i = 0; i < funcArgs.length; i++) {
result = funcArgs[i](result);
}
return result;
};
}
// reduce 적용한 버전 훨씬 갈끔 👍
function composeSimple(...funcArgs) {
return initVal => funcArgs.reduce((acc, elem) => {
return elem(acc);
}, initVal);
}
// compose를 통해 함수들이 순서대로 적용된다는 것이 직관적으로 드러납니다.
// 각각의 함수는 다른 목적을 위해 재사용(reuse) 될 수 있습니다.
// 합성함수를 통해서 컴포넌트를 재사용하고, 직관적으로 로직을 파악 가능하다
// 짱 좋군요 😍😍😍😍
const getAverageAgeOfMale = compose(
getOnlyMales, // 배열을 입력받아 배열을 리턴하는 함수
getOnlyAges, // 배열을 입력받아 배열을 리턴하는 함수
getAverage // 배열을 입력받아 `number` 타입을 리턴하는 함수
);
const result = getAverageAgeOfMale(data);
console.log(result); // --> 26
some 콜백함수를 만족하는 조건이 하나라도 있는지
every 모두 콜백함수를 만족하는지