JavaScript 函数的 length:声明了三个参数,为什么只报告一个
写通用调用适配器时,有人把fn.length当成函数能接收的参数个数,于是只转发这么多项。一个函数原本声明path、mode、retries三个位置,给mode加上默认值以后,length却从三变成一;后面的重试次数也可能被适配器意外丢掉。
对于下面这些普通函数,length是声明形成的计数信息:从左侧开始,只计入第一个带默认值的参数之前的位置。rest参数不贡献这个数;一个解构模式则作为一个位置计数,不按里面绑定了几个名称累加。它不会限制调用者传入更多参数。
以下完整程序保存为demo.mjs,执行node demo.mjs。已在Node.js v24.19.0运行并通过断言,只调用几个内存函数。route另外记录arguments.length,用来与函数自身的length作直接对照。
AI模型生成的概念插图:计量括号只覆盖前面的一个位置,而后方条目仍可进入接收碗,表示声明计数并不是输入上限;不是软件截图。
完整可运行程序
import assert from 'node:assert/strict';
function route(path, mode = 'safe', retries) {
return {path, mode, retries, received: arguments.length};
}
function collect(head, ...tail) {return [head, tail];}
function pair({left, right}, [first, second]) {
return left + right + first + second;
}
assert.equal(route.length, 1);
assert.equal(collect.length, 1);
assert.equal(pair.length, 2);
console.log('declared lengths:', route.length, collect.length, pair.length);
const explicit = route('/demo', 'fast', 3);
assert.deepEqual(explicit,
{path: '/demo', mode: 'fast', retries: 3, received: 3});
console.log('three supplied:', JSON.stringify(explicit));
const withDefault = route('/demo', undefined, 4);
assert.deepEqual(withDefault,
{path: '/demo', mode: 'safe', retries: 4, received: 3});
console.log('default used:', JSON.stringify(withDefault));
const one = route('/demo');
assert.equal(one.retries, undefined);
assert.equal(one.received, 1);
assert.deepEqual(collect('A', 'B', 'C'), ['A', ['B', 'C']]);
assert.equal(pair({left: 1, right: 2}, [3, 4]), 10);
console.log('one supplied:', one.received, one.retries);
console.log('rest result:', JSON.stringify(collect('A', 'B', 'C')));本次实际输出
declared lengths: 1 1 2
three supplied: {"path":"/demo","mode":"fast","retries":3,"received":3}
default used: {"path":"/demo","mode":"safe","retries":4,"received":3}
one supplied: 1 undefined
rest result: ["A",["B","C"]]三个函数为什么分别是一、一、二
route的第二个位置mode有默认值,因此计数停在它之前,只留下path,length为一。第三个retries没有默认值,也不会重新恢复计数。不能把这个规则简化成“统计所有没有默认值的参数”,否则本例就会错误地算出二。
collect只有head贡献一个位置,后面的rest用于收集多余实参,但不计入length。pair内部拆出了left、right、first、second四个名字,调用接口却只有一个对象位置和一个数组位置,所以length为二。
传了多少,要在本次调用里观察
three supplied打印path、fast、三次重试以及received为三,说明route.length为一并没有阻止三个参数全部进入。arguments.length属于这次普通函数调用;route.length属于函数对象的声明信息,两者可以同时正确而数字不同。
default used同样received为三:调用者明确传了undefined给第二位置,因此默认值safe生效,但那个位置仍然算一个已传入的实参。第三位置的四也照常保留。是否使用默认值,与本次调用提供了几个位置,不是同一项判断。
少传参数也不会由length自动报错
one supplied显示received为一、retries为undefined。JavaScript在本例没有自动报参数不足;业务如果要求retries必须是非负整数,就应在入口明确检查,而不能从函数length推导出完整的必填字段规则。
rest result则把B、C收进tail数组,进一步表明length为一不等于只能处理一个值。若适配器按这个数裁切实参,恰好会破坏rest设计。回调转发通常应依据明确的接口约定,将允许的参数原样交给目标函数。
排查框架集成时,先确认框架是否把函数声明长度当成协议信号;若确实如此,添加默认值或改成rest包装可能改变它的分支。测试应同时覆盖函数元数据、实际收到的参数和业务校验结果,不要只看直接调用一次仍能返回就认为包装层也保持兼容。
官方资料核验日期:2026年10月2日。上述输出来自本文完整程序的本地执行,全部断言通过,退出状态为零。


