JavaScript中的闭包-出了什么问题?
我试图在下一步结束时:JavaScript中的闭包-出了什么问题?,javascript,closures,Javascript,Closures,我试图在下一步结束时: function func(number) { var result = number; var res = function(num) { return result + num; }; return res; } var result = func(2)(3)(4)(5)(3); console.log(result); // 17 我需要接收2+3+4+5+3=17 但我有一个错误:未捕获类型错误:数字不是函数您
function func(number) {
var result = number;
var res = function(num) {
return result + num;
};
return res;
}
var result = func(2)(3)(4)(5)(3);
console.log(result); // 17
我需要接收2+3+4+5+3=17
但我有一个错误:未捕获类型错误:数字不是函数您误用了函数
func(2)
返回res
函数。使用
(3)
调用该函数将返回数字5
(通过返回结果+num
)
5
不是一个函数,因此(4)
给出了一个错误。嗯,(2)(3)部分是正确的。调用func(2)将返回res
,这是一个函数。但是,调用(3)将返回res
的结果,这是一个数字。所以当你试着打电话(4)时,问题就来了
对于您试图做的事情,我不知道Javascript如何预测您处于链的末端,并决定返回一个数字而不是一个函数。也许您可以使用对象属性返回一个具有“result”属性的函数,但我最想知道的是,为什么您要这样做。显然,对于您的特定示例,最简单的方法就是将数字相加,但我猜您在某些方面做得更进一步。如果您想继续调用它,您需要不断返回函数,直到您需要答案为止。e、 g.用于5次调用
function func(number) {
var result = number,
iteration = 0,
fn = function (num) {
result += num;
if (++iteration < 4) return fn;
return result;
};
return fn;
}
func(2)(3)(4)(5)(3); // 17
函数func(数字){
var结果=数字,
迭代=0,
fn=函数(num){
结果+=num;
如果(++迭代<4),则返回fn;
返回结果;
};
返回fn;
}
func(2)(3)(4)(5)(3);//17
你也可以做一些更长的事情,就像这样
function func(number) {
var result = number,
fn = function () {
var i;
for (i = 0; i < arguments.length; ++i)
result += arguments[i];
if (i !== 0) return fn;
return result;
};
return fn;
}
func(2)(3, 4, 5)(3)(); // 17
函数func(数字){
var结果=数字,
fn=函数(){
var i;
对于(i=0;i
您必须以某种方式通知链的末端,在那里您将返回结果编号,而不是另一个函数。您可以选择:
- 让它返回一个固定次数的函数——这是使用语法的唯一方法,但它很无聊。看看@PaulS的答案。您可以进行第一次调用(
)来提供参数数量func(n)
sum
- 在某些情况下返回结果,例如在调用函数时没有参数(@PaulS的第二个实现)或使用特殊值(
在@AmoghTalpallikar的答案中)null
- 在函数对象上创建一个返回值的方法
非常适合,因为将函数强制转换为基元值时将调用它。在行动中看到它:valueOf()
function func(x) { function ret(y) { return func(x+y); } ret.valueOf = function() { return x; }; return ret; } func(2) // Function func(2).valueOf() // 2 func(2)(3) // Function func(2)(3).valueOf() // 5 func(2)(3)(4)(5)(3) // Function func(2)(3)(4)(5)(3)+0 // 17
reduce
:
function sum(a, b) {
return a + b;
}
a = [2, 3, 4, 5, 3];
b = a.reduce(sum);
另一种解决方案可能只是调用不带params的函数以获得结果,但如果使用params调用函数,则会将其添加到总和中
函数添加(){
var总和=0;
var闭包=函数(){
sum=Array.prototype.slice.call(参数).reduce(函数总数,num){
返回total+num;
},总和);
return arguments.length?闭包:sum;
};
返回closure.apply(null,参数);
}
console.log(添加(1,2,7)(5)(4)(2,3)(3.14,2.86));//函数(){}
console.log(添加(1,2,7)(5)(4)(2,3)(3.14,2.86)();//30;
我们可以使用两个助手函数identity
和sumk
轻松实现它
sumk
使用一个continuation来保存挂起的add计算堆栈,并在调用第一个()
时使用0
展开堆栈
const identity=x=>x
常数sumk=(x,k)=>
x==未定义?k(0):y=>sumk(y,next=>k(x+next))
const sum=x=>sumk(x,恒等式)
console.log(sum())//0
console.log(sum(1)()//1
console.log(sum(1)(2)()//3
console.log(sum(1)(2)(3)()//6
console.log(sum(1)(2)(3)(4)()//10
console.log(sum(1)(2)(3)(4)(5)()//15
这伤害了我的大脑。。您可以返回一个函数或一个数字,而不是两者都返回。@MikeChristensen:实际上,您可以通过检查参数来返回这两个函数。length
@SLaks-Oh并在链的末尾放一个()
?是的,这是一个惹恼同事的聪明方法。你有什么理由不能使用func(2,3,4,5,3)
并修改你的函数以适应这种设置吗?虽然你有一个简单的例子,但这样做更有意义,而不是不断调用函数?…可能是@user2056866的重复。很难看出这有什么实际用途,所以这很可能是家庭作业。你想做一个递归函数吗?如果是这样的话,你就有点不对劲了。只是为了有趣,我试图通过闭包来完成这个任务。@user2056866:试试我的答案。这不完全是你想要的,但几乎是一样的。是的,这只是为了有趣。但我还是不明白怎么会是对的。就像我说的,你用这种方式称呼它的整个方法都很奇怪。返回具有链可调用函数的对象会更容易接受吗?例如,func().addmore(3).addmore(5).addmore(7).getResult()
?这通常是JQuery所做的。我并没有对您的答案投反对票,但它只适用于这么多的()。它不是动态的。@AmoghtalPalikar好吧,我是为OPs编写的,但在我的版本中,它的工作原理略有不同。如果我打电话。f(4)(5)结果变为9。nxt时间f(