Estoy tratando de volver a implementar la función de redacción de redux , en lugar de usar reduce , uso un bucle for, aquí está mi código:
function compose(...funcs) { if (funcs.length === 0) { return (arg) => arg; } if (funcs.length === 1) { return funcs[0]; } let result; for (let i = funcs.length - 1; i > -1; i--) { result = result ? (...args) => funcs[i](result(...args)) : (...args) => funcs[i](...args); } return result; } // test function fn1(x) { return x + 1; } function fn2(x) { return x * 10; } function fn3(x) { return x - 1; } console.log(compose(fn3, fn2, fn1)(10)); // 109Se espera que registre 109 ya que (10 + 1) * 10 - 1 es 109, sin embargo, me da este error:
RangeError: Maximum call stack sizeParece que estoy haciendo algo de recursividad, pero todo lo que hice fue solo un bucle for, ¿no estoy seguro de dónde está el problema de mi código?
Creo que el problema es como el siguiente ejemplo:
a = () => 2; a = () => 3 * a(); console.log(a); // this prints () => 3 * a() in console // so when you call a(), it will call 3 * a(), which will again call 3 * a() and so on // leading to infinite recursion Mi solución es ligeramente diferente al usar la función de vinculación basada en este bind de referencia: https://stackoverflow.com/a/6772648/4688321 .
Creo que bind crea una nueva copia del result de la función y la vincula a un nuevo objeto. No usar bind conduce a la recursividad porque entonces el código se vuelve como el ejemplo anterior, result de llamadas a result .
function compose(...funcs) { if (funcs.length === 0) { return (arg) => arg; } if (funcs.length === 1) { return funcs[0]; } let result; for (let i = funcs.length - 1; i > -1; i--) { if (i == funcs.length - 1) result = (...args) => funcs[i](...args); else { let temp = result.bind({}); result = (...args) => funcs[i](temp(...args)); } } return result; } // test function fn1(x) { console.log("fn1"); return x + 1; } function fn2(x) { console.log("fn2"); return x * 10; } function fn3(x) { console.log("fn3"); return x - 1; } //console.log(compose(fn3, fn2, fn1)); let ret = compose(fn3, fn2, fn1); console.log(ret(10)); // 109En lugar de tratar de combinar funciones en el momento de compose , parece mucho más fácil combinarlas en el momento en que se llama a la función resultante:
function compose(...funcs) { if (funcs.length === 0) { return (arg) => arg } return function (...args) { let result = funcs .at (-1) (...args) for (let i = funcs.length - 2; i > -1; i--) { result = funcs [i] (result) } return result } } // test function fn1(x) { return x + 1; } function fn2(x) { return x * 10; } function fn3(x) { return x - 1; } console.log(compose(fn3, fn2, fn1)(10)); // 109 Sin embargo, de nuevo, reduce make para una implementación mucho más limpia:
const compose = (...fns) => (arg) => fns .reduceRight ((a, fn) => fn (a), arg)o si desea permitir que la función más a la derecha reciba múltiples variables, entonces
const compose = (...fns) => (...args) => fns .reduceRight ((a, fn) => [fn (...a)], args) [0]