const reducer = (f, acc, iter) => {
if(!iter){
iter = acc[Symbol.iterator]();
acc = iter.next().value;
}
for(const a of iter){
acc = f(a,acc);
}
return acc;
}
const add = (a,b)=>a+b;
console.log('reducer: ',reducer(add,[1,3,5,7,11,13]));
reducer 함수를 직접 제작하였는데 이는 iterator protocall을 따르는 값이 iter인 경우 모두 적용이 된다.
const reducer = (f, acc, iter) => {
if(!iter){
iter = acc[Symbol.iterator]();
acc = iter.next().value;
}
for(const a of iter){
acc = f(a,acc);
}
return acc;
}
const add = (a,b)=>a+b;
console.log('reducer: ',reducer(add,[1,3,5,7,11,13]));
// go Fn
const go = (...args) => reducer((f,a)=>f(a),args)
go(
0,
a=>(a+1),
a=>(a+10),
a=>(a+100),
console.log
)
go 함수는 reducer 함수에 들어갈 인자들을 받아준다.
acc 값이 되어줄 0과 나머지는 보조 함수들을 넣어준다.
go = (...args) => ...
에서 ...args
는 [0, a=>a+1, a=>a+10, a=>a+100, console.log]
와 같다.
배열을 전달 받았으므로 reducer 함수의 두 번째 인자가 되면 되고,
reducer 함수는 배열의 0 번째 인자를 acc로 첫 번째 인자로 받은 보조 함수를 실행한다.
go = (...args) => reducer((f,a)=>f(a),args)
에서 reducer((a,f)=>f(a)
함수는 a의 값으로 0 번째 인자인 0을,
f = a=>a+1을 사용한다.
왜 이렇게 되는가?
const reducer = (f, acc, iter) => {
if(!iter){
iter = acc[Symbol.iterator]();
acc = iter.next().value;
}
for(const a of iter){
acc = f(a,acc);
}
return acc;
}
for...of
문에서 acc의 값은 iter[0]의 값과 같다.
따라서 reducer의 첫 인자인 f(보조함수)의 두번째 인자는 iter[0]의 값이고
a의 값은 iter[1]의 값이다.
여기까지 하고 다시 go 함수에 넘긴 인자를 보자.
go(0, a=>a+1,...)
iter[0] = 0 이 되는 것이고
iter[1] = a=>a+1 이 된다.
0은 reducer의 if 문에의해 for...of
문의 순회에서 벗어나게되고
첫 for...of
문의 대상은 보조함수인 a=>a+1
이 되므로
첫 for...of
문은 이런 식으로 이루어진다.
for(const i of iter){ acc = f(a=>a+1,0)=>{ return 0=>0+1 } }
둘 째는 함수가 담긴 iterable 객체에서 다음 함수르 꺼내오게 된다.
acc = f(a=>a+10, 1) => 1 => 1+10
acc의 값은 함수의 리턴값으로 누적되어 1 -> 11이 된다.
이를 반복하는 것이 go 함수이다.