为何JavaScript中Function.length属性会排除剩余参数?
理解JavaScript中的函数元数(arity)与剩余参数的length陷阱
最近在探索RambdaJS的柯里化函数时,我发现了一个很有意思的用法,举个直观的例子:
var addFourNumbers = (a, b, c, d) => a + b + c + d; var curriedAddFourNumbers = R.curry(addFourNumbers); var f = curriedAddFourNumbers(1, 2); var g = f(3); g(4); //=> 10
很多函数式编程语言原生就支持柯里化,但在JS里这操作看起来有点像"魔法"。而要搞懂柯里化的底层逻辑,首先得知道怎么判断一个函数的元数(arity)——也就是它预期接收的参数数量。
其实答案特别简单,直接用函数的length属性就行,相关定义是这样的:
length属性表示函数预期接收的参数数量。
看个基础示例就懂了:
function func1() {} function func2(a, b) {} console.log(func1.length); // expected output: 0 console.log(func2.length); // expected output: 2
不过这里有个容易踩坑的点:剩余参数会被length属性排除在外,比如这个例子:
function a(...d) { console.log(d) } console.log(a.length); // expected output: 0
乍一看有点奇怪——函数a明明定义了接收一个参数d(虽然是数组形式),为什么length会是0?这到底是合理设计还是JS又一个让人吐槽的"WAT"特性?
其实这是有意为之的设计,不是bug。原因在于:剩余参数的本质是收集所有未被显式声明的参数,它并不代表函数预期接收的固定参数数量。length属性的核心语义是反映函数定义中显式声明的、非剩余参数的个数——简单说就是,调用这个函数时"至少"需要传入多少个参数。
比如如果我们写:
function b(x, ...y) {} console.log(b.length); // expected output: 1
这里length是1,因为x是必须显式传入的第一个参数,而...y是用来兜底处理额外参数的,不属于"预期必须传入"的范畴。
当函数只有剩余参数时,length为0其实也符合这个逻辑:这个函数没有要求调用者必须传入任何参数,所有传入的参数都会被收集到剩余参数里。虽然直观上可能有点反常识,但这是JS为了保持length属性语义一致性做出的选择,算不上"WAT"特性,而是有明确设计意图的。
内容的提问来源于stack exchange,提问作者zooblin
相关产品推荐
相关产品推荐

