在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但是我得到一个错误:未捕获TypeError:数字不是一个函数
你在滥用你的function。
func(2)
返回res
函数。
用(3)
调用该函数返回数字5
(通过return result + num
)。
5
不是一个函数,所以(4)
给出一个错误。
你不知何故必须指示链的结束,你将返回结果号而不是另一个函数。 你有select:
- 使它返回一个固定次数的函数 – 这是使用像你这样的语法的唯一方法,但它是无聊的。 看看@PaulS'的答案。 你可能会做第一个调用(
func(n)
)提供多less个参数sum
的curry 。 - 在某些情况下返回结果,比如当函数被调用时没有参数(@PaulS的第二个实现)或者一个特殊的值(在@ AmoghTalpallikar的答案中为
null
)。 -
在函数对象上创build一个返回值的方法。
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
那么,(2)(3)部分是正确的。 调用函数(2)将返回你的res
,这是一个函数。 但是,调用(3)将返回res
的结果,这是一个数字。 所以当你尝试打电话时,问题就来了(4)。
对于你想要做的事,我不明白Javascript是如何预测你是在链的末尾,并决定返回一个数字,而不是一个函数。 也许你可以以某种方式返回一个具有 “结果”属性的函数使用对象的属性,但大多数我只是好奇你为什么要尝试这样做的事情。 显然,对于你的具体例子来说,最简单的方法就是把数字加在一起,但是我估计你会进一步做些什么。
我把这个标记为重复的,但是因为这个替代方法也没有从这个问题中删除,我将在这里添加它。 如果我正确地理解了为什么你会认为这很有趣(有一个随机应用于值列表的任意函数,积累结果),你还应该看看reduce
:
function sum(a, b) { return a + b; } a = [2, 3, 4, 5, 3]; b = a.reduce(sum);
另一个解决scheme可能只是调用没有参数的函数,以获得结果,但如果你用params调用它会增加总和。
function add() { var sum = 0; var closure = function() { sum = Array.prototype.slice.call(arguments).reduce(function(total, num) { return total + num; }, sum); return arguments.length ? closure : sum; }; return closure.apply(null, arguments); } console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)); // function(){} console.log(add(1, 2, 7)(5)(4)(2, 3)(3.14, 2.86)()); // 30;
我们可以使用一些辅助函数identity
和sumk
。
sumk
使用延续来保留待处理的加法计算的堆栈,并且每当第一个()
被调用时用0
解开堆栈。
const identity = x => x const sumk = (x,k) => x === undefined ? k(0) : y => sumk(y, next => k(x + next)) const sum = x => sumk(x, identity) 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
如果你想继续调用它,你需要继续返回一个函数,直到你想要你的答案。 例如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
你也可以做更长的东西,像这样工作
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