实现 redux compose 函数但得到 RangeError
Implement redux compose function but get RangeError
我正在尝试重新实现 redux compose 函数,而不是使用 reduce
我使用 for 循环,这是我的代码:
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)); // 109
由于 (10 + 1) * 10 - 1 是 109,因此预计会记录 109,但是它给了我这样的错误:
RangeError: Maximum call stack size
看起来我在做一些递归,但我所做的只是一个for循环,不知道我的代码哪里有问题?
我认为这个问题就像下面的例子:
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
我的解决方案与基于此参考 link 使用 bind
函数略有不同:。
我认为 bind
创建函数的新副本 result
并将其绑定到新对象。不使用 bind
会导致递归,因为这样代码就会像上面的例子一样,result
调用 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)); // 109
与其在 compose
时尝试组合函数,不如在 调用 时组合函数似乎容易得多:
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
但是,reduce
再次使实现更加简洁:
const compose = (...fns) => (arg) =>
fns .reduceRight ((a, fn) => fn (a), arg)
或者如果你想让最右边的函数接收多个变量,那么
const compose = (...fns) => (...args) =>
fns .reduceRight ((a, fn) => [fn (...a)], args) [0]
我正在尝试重新实现 redux compose 函数,而不是使用 reduce
我使用 for 循环,这是我的代码:
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)); // 109
由于 (10 + 1) * 10 - 1 是 109,因此预计会记录 109,但是它给了我这样的错误:
RangeError: Maximum call stack size
看起来我在做一些递归,但我所做的只是一个for循环,不知道我的代码哪里有问题?
我认为这个问题就像下面的例子:
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
我的解决方案与基于此参考 link 使用 bind
函数略有不同:。
我认为 bind
创建函数的新副本 result
并将其绑定到新对象。不使用 bind
会导致递归,因为这样代码就会像上面的例子一样,result
调用 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)); // 109
与其在 compose
时尝试组合函数,不如在 调用 时组合函数似乎容易得多:
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
但是,reduce
再次使实现更加简洁:
const compose = (...fns) => (arg) =>
fns .reduceRight ((a, fn) => fn (a), arg)
或者如果你想让最右边的函数接收多个变量,那么
const compose = (...fns) => (...args) =>
fns .reduceRight ((a, fn) => [fn (...a)], args) [0]