前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库函数 length 属性 默认参数 剩余参数影响
JavaScript函数与作用域

函数的 length 是什么?加了默认参数和剩余参数后会变吗?

length 是函数声明里的形参个数,不是调用时传了几个参数。它只数到第一个带默认值的参数之前,后面的都不算;剩余参数 ...args 不算;一个解构参数整体算一个。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#函数与作用域
先看核心答案读代码示例
理解线索

`length` 怎么数

  1. 普通形参从左往右一个一个数,遇到默认参数或剩余参数就停
  2. 默认参数它本身和它后面的所有形参都不计入,哪怕后面的没有默认值
  3. 解构参数{ id, name } 这种整体只占一个位置,算 1

想知道这次调用实际传了几个参数,要看函数内部的 arguments.length,或者用剩余参数收集后看数组长度。

核心回答

先记住这个答案

函数的 length 表示它声明了几个「必须传」的形参,是在定义时就确定的,和调用时传了几个参数无关。计数规则是从左往右数,数到第一个带默认值的参数就停下,它和它后面的参数都不算。剩余参数 ...args 也不算。解构参数不管里面有几个字段,整体只算一个。

  • length 是声明的形参数,和实际传参无关
  • 从第一个默认参数开始,后面的都不计
  • 剩余参数不计,解构参数算一个
  • bind 预置几个参数,length 就减几,最小为 0

逐个验证计数规则

把默认参数、剩余参数和解构放在不同位置,直接打印 length。

不同形参写法下的 lengthJavaScript
function a(x, y, z) {
  return arguments.length // 实际传入的参数个数
}
function b(x, y = 1, z) {} // y 有默认值,从 y 开始都不算
function c(x, ...rest) {} // rest 不算
function d({ id, name }, [first]) {} // 两个解构参数,各算一个
const e = (...args) => {}

console.log(a.length, a(1, 2, 3, 4))
console.log(b.length)
console.log(c.length)
console.log(d.length)
console.log(e.length)
查看输出与解释
3 4
1
1
2
0

a 声明了三个形参,length 就是 3,调用时传了四个,arguments.length 是 4,两者没关系。b 里的 z 虽然没写默认值,但它在 y 后面,也不算,所以只有 x 一个。c 只数 x。d 有两个解构参数,算 2。e 只有剩余参数,是 0。 为什么要这么设计?可以把 length 理解成「调用方至少应该传几个参数」。有默认值的参数本来就是可选的,而一旦中间出现了可选参数,后面的参数在位置上也就没法强制要求了,所以干脆停止计数。

bind 和包装函数会改掉 length

bind 返回的新函数,length 等于原函数的 length 减去预置参数的个数,最小是 0。比如 function f(a, b, c) {},f.bind(null, 1).length 是 2,f.bind(null, 1, 2, 3, 4).length 是 0。只绑定 this、不预置参数时,length 不变。

更常见的坑是自己写的包装函数。节流、防抖、日志装饰器这类工具,内部通常返回 (...args) => fn(...args),包装后的函数 length 变成了 0,原来的信息丢了。

柯里化为什么会被 length 坑
很多 curry 实现用 fn.length 判断参数凑够了没有。原函数一旦加了默认参数,比如 (a, b, c = 0) => a + b + c,length 从 3 变成 2,传完 a、b 就提前执行了,c 再也传不进去。被防抖包装过的函数 length 是 0,curry 会在第一次调用时就直接执行。所以靠谱的 curry 都允许手动传入参数个数,不完全依赖 length。
回答前,多想一步

容易答错的地方

以为 length 是所有形参的个数
默认参数会截断计数,剩余参数也不算。function f(a = 1, b) {} 的 length 是 0,不是 1 也不是 2。
以为 length 会随调用变化
length 是函数对象上的属性,定义时就定好了。想知道这次传了几个参数,要在函数内部看 arguments.length 或者剩余参数数组的长度。
以为可以直接给 length 赋值
length 是只读的,fn.length = 5 不会生效,严格模式下还会抛 TypeError。它是可配置的,真要改只能用 Object.defineProperty,但业务代码里基本没有理由这么做。
试着用自己的话回答

面试官还会怎么问?

arguments.length 和 fn.length 有什么区别?

fn.length 是函数声明的形参数,在函数外面就能读,永远不变。arguments.length 是这一次调用实际传入的参数个数,只能在函数内部读,每次调用都可能不一样。

Express 怎么通过参数个数区分错误处理中间件?

Express 会检查中间件函数的 length,是 4 的就当作错误处理中间件,签名是 (err, req, res, next)。所以错误处理中间件即使用不到 next,也必须把四个参数都写上,写成三个它就会被当成普通中间件。

TypeScript 里的可选参数会影响 length 吗?

function f(a: number, b?: number) 编译成 JavaScript 后就是 function f(a, b),问号只存在于类型层面,length 是 2。真正写了默认值 b = 0 时,结果还要看编译产物:保留默认参数语法的编译目标下 length 是 1;如果编译到 ES5,默认值会被改写成函数体里的判断,形参列表还是 (a, b),length 又变回 2。拿不准时直接在构建产物里打印一下。

从一道题,走向一组知识

把知识连起来

函数与作用域

什么是词法作用域?作用域链是怎么形成的?

默认参数的表达式会在参数自己的作用域里求值,它能读到哪些变量由词法作用域决定。

函数与作用域

匿名函数和箭头函数的 name 是怎么来的?

name 和 length 都是函数对象自带的只读元数据,一个记名字,一个记形参个数,常被一起问。

参考资料

  • JavaScript:函数与作用域参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 逐个验证计数规则
  3. bind 和包装函数会改掉 length
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑