云浮市网站建设_网站建设公司_色彩搭配_seo优化
2026/1/14 9:43:32 网站建设 项目流程


别再搞混了!arguments对象和rest参数到底有啥不一样?

  • 别再搞混了!arguments对象和rest参数到底有啥不一样?
    • 开场白:当年我把面试官聊懵了
    • 先给俩货拍个证件照,省得脸盲
      • 老古董 arguments
      • 新生代 rest
    • 现场翻车实录:一行代码看出亲妈和保姆的区别
    • 箭头函数里根本没有 arguments?对,但故事得补全
    • 类数组转真数组的三板斧,面试常问!
    • 性能深坑:别再在热路径里访问 arguments
    • 递归场景:rest 爽到飞起,但爆栈别怪我
    • arguments.callee 被禁之后,匿名递归怎么苟?
    • 动态获取参数个数:length 行为大不同
    • 模拟函数重载?可以,但真的值得吗
    • TypeScript 写 rest:不加类型让你怀疑人生
    • class 方法里别乱用 arguments,this 可能让你哭
    • 实战小技巧:rest + 解构,前几个我要,剩下的打包
    • 非严格模式下改 arguments,会反向污染实参?
    • 把 arguments 当普通对象遍历?隐藏属性在盯着你
    • 兼容老浏览器又想用 rest?Babel 教你做人
    • 调试小贴士:控制台自动展开 arguments 别慌
    • 谣言终结:arguments 真的被废弃了吗?
    • 一张脑图总结(语音转文字,脑图在脑子里)
    • 彩蛋:用 rest 写个“任意参数管道”玩玩
    • 收尾:别再傻傻分不清

别再搞混了!arguments对象和rest参数到底有啥不一样?

——深夜语音转文字版,边吐槽边把坑填平


开场白:当年我把面试官聊懵了

先交代背景,免得你以为我在吹牛逼。
三年前我拎着半桶水的 JS 去面试,对面小哥邪魅一笑:“说说 arguments 和 rest 区别。”
我张嘴就来:“不都是收参数的吗?rest 就是语法糖吧!”
小哥没说话,默默在纸上写了两行代码,推到我面前。十秒后,我社死。
今天把那段社死经历翻出来,揉碎喂给你们,能救一个是一个。


先给俩货拍个证件照,省得脸盲

老古董 arguments

出生年份:上古(ES1)
身份:类数组对象,长得跟数组撞脸,但没护照(原型链上没 Array)
脾气:怪异,非严格模式下还能改成员,一不留神就把实参带沟里
隐藏技能:arguments.callee指向自己,可惜被 strict 模式拉黑了

新生代 rest

出生年份:ES6,带光环
身份:真 · 数组,全家桶方法都能用
脾气:佛系,只读,不乱动外层变量
隐藏技能:想拿几个就拿几个,剩余的全打包,搭配解构食用更佳


现场翻车实录:一行代码看出亲妈和保姆的区别

// 场景:老板让把收到的参数翻倍后求和functionoldWay(){// 1. arguments 先冒充数组constnums=Array.prototype.slice.call(arguments);// 老手艺,又叫“借刀杀人”returnnums.reduce((s,n)=>s+n*2,0);}functionnewWay(...nums){// 2. rest 天生就是数组,直接开干returnnums.reduce((s,n)=>s+n*2,0);}console.log(oldWay(1,2,3));// 12console.log(newWay(1,2,3));// 12

看着结果一样,但老Way里那句slice.call就是脱裤子放屁——多此一举。
而且slice在 V8 里会触发一次完整的对象复制,参数一多,性能肉眼可见往下掉。
面试官当初就给我甩了 1w 个数字,老Way直接卡成 PPT,newWay 还丝滑得像个渣男。


箭头函数里根本没有 arguments?对,但故事得补全

constfoo=()=>console.log(arguments);// 报错:arguments is not defined

箭头函数没自己的arguments,它用的是外层函数(或全局)的。
想偷懒?直接 rest:

constfoo=(...args)=>console.log(args);// 完美,args 是真数组

记住:箭头函数 + rest 参数,才是现代前端人的基本修养,别再写const self = this那种考古代码了。


类数组转真数组的三板斧,面试常问!

  1. 老派刀法:Array.prototype.slice.call(arguments)
    兼容 IE 6,但慢,且 strict 下 callee 拿不到。

  2. ES6 语法糖:const arr = [...arguments]
    一句话,颜值高,性能比 slice 好一丢丢。

  3. 官方外挂:Array.from(arguments)
    专治各种类数组,还能顺便 map:
    Array.from({length: 5}, (_, i) => i * i) // [0, 1, 4, 9, 16]


性能深坑:别再在热路径里访问 arguments

V8 的“优化杀手”名单里,arguments高挂榜首。
只要你在函数里对arguments有“不规矩”操作——比如arguments[i].length、或者把它当对象塞到另一个函数——TurboFan 直接躺平,回退到字节码解释器,性能雪崩。
rest 参数因为天生数组,JIT 能提前做类型推导,反而一路绿灯。
口说无凭,跑个分:

// benchmark:累加 100 万个数字functionwithArguments(){lets=0;for(leti=0;i<arguments.length;i++)s+=arguments[i];returns;}functionwithRest(...args){lets=0;for(constnofargs)s+=n;returns;}constdata=Array.from({length:1e6},()=>Math.random());console.time('arg');withArguments(...data);console.timeEnd('arg');console.time('rest');withRest(...data);console.timeEnd('rest');

Node 20 下差距 3~5 倍,自己玩去吧。


递归场景:rest 爽到飞起,但爆栈别怪我

写个累加递归感受一下:

// rest 版,颜值 100 分constsum=(first,...rest)=>rest.length===0?first:first+sum(...rest);console.log(sum(1,2,3,4));// 10

优雅是优雅,可 JS 没有尾递归优化,1w 个数字直接Maximum call stack size exceeded
真要在生产里玩递归,老老实实改循环,或者上 trampoline 蹦床模式,别拿业务数据开玩笑。


arguments.callee 被禁之后,匿名递归怎么苟?

strict 模式里arguments.callee被枪毙,-named 匿名函数表达式了解一下:

constfactorial=functionf(n){returnn<=1?1:n*f(n-1);};

给函数起个内部名f,作用域内永远指向自己,就算外部变量被覆盖也稳如老狗。
不想起名?那就别写匿名递归,代码可读性第一。


动态获取参数个数:length 行为大不同

functionfoo(a,b,c){}console.log(foo.length);// 3 形参个数functionbar(...args){}console.log(bar.length);// 0 rest 不参与计数

arguments.length是实际传了几个,
func.length是定义时写了几人,
rest 参数在定义阶段不算人头,面试常考,记住喽。


模拟函数重载?可以,但真的值得吗

Java 党最爱重载,JS 党没有,于是有人拿arguments.length硬拗:

functionload(){if(arguments.length===1)returnloadUser(arguments[0]);if(arguments.length===2)returnloadUserWithRole(arguments[0],arguments[1]);thrownewTypeError('参数不对');}

功能能跑,但维护起来想打人。
TypeScript 时代,直接上联合类型 + 泛型,编译期就把错误拍死,不香吗?


TypeScript 写 rest:不加类型让你怀疑人生

functionpush(...args){// 报错:Parameter implicitly has an 'any' typeconsole.log(args);}

正解:

functionpush<T>(...args:T[]):T[]{returnargs;}

一行泛型,世界清静。
别偷懒写any[],那样还不如回 JS 放羊。


class 方法里别乱用 arguments,this 可能让你哭

classCounter{count=0;inc(){// 这里如果写成 [...arguments],this 指向没问题// 但你要是手贱把 arguments 传给外部函数,this 就丢了[].slice.call(arguments).forEach(n=>this.count+=n);}}

正确姿势:直接 rest,少碰瓷this

inc(...nums){nums.forEach(n=>this.count+=n);}

实战小技巧:rest + 解构,前几个我要,剩下的打包

functionlogFirstTwoAndRest(first,second,...others){console.log('老大:',first);console.log('老二:',second);console.log('小弟们:',others.join(' | '));}logFirstTwoAndRest('a','b','c','d','e');// 老大:a// 老二:b// 小弟们:c | d | e

写中间件、拦截器时这招超香,前面拿配置,后面传可变参数,代码干净得像刚洗的袜子。


非严格模式下改 arguments,会反向污染实参?

真的,童叟无欺:

functionsneaky(a,b){arguments[0]=100;console.log(a);// 100}sneaky(1,2);

strict 模式下相安无事,非严格模式直接改原变量,老项目里这种黑魔法一抓一把,升级 TS 记得加"strict": true,不然半夜被坑哭。


把 arguments 当普通对象遍历?隐藏属性在盯着你

functionshowHidden(){for(constkeyinarguments){console.log(key);// 0 1 2 ...}console.log(Object.keys(arguments));// ['0', '1', '2']console.log(arguments.hasOwnProperty('callee'));// true,非 strict}

calleecaller这些属性平时隐身,一for...in就蹦出来,很容易踩雷。
Object.keys不会拿不可枚举属性,但for...in会,写工具库时别混用。


兼容老浏览器又想用 rest?Babel 教你做人

安装一条龙:

npmi -D @babel/preset-env

.babelrc 里写:

{"presets":[["@babel/preset-env",{"targets":{"ie":"11"}}]]}

写最潮的语法,让 Babel 帮你翻译成 IE 能看懂的古代汉语。
打包体积会大一点,但业务要兼容,没办法。


调试小贴士:控制台自动展开 arguments 别慌

Chrome DevTools 里console.log(arguments)会直接展开成数组样式,那是浏览器 UI 在帮你,不等于它是真数组。
想看庐山真面目:

console.dir(arguments);

隐藏属性、原型链一目了然,面试时现场演示,对面小姐姐直呼专业。


谣言终结:arguments 真的被废弃了吗?

ECMA 规范里从没写“deprecated”,只是不推荐使用。
某些极端场景,比如高性能模板引擎、代码混淆器,仍然靠arguments省字节。
再说一遍:不是不能用,而是“大部分场景你有更好的选择”。


一张脑图总结(语音转文字,脑图在脑子里)

  1. 新代码默认 rest,真数组、无性能坑、结合解构爽歪歪。
  2. 老库维护、强依赖 callee、要跑 IE8?再请 arguments 出山。
  3. 箭头函数里没得选,只能 rest。
  4. 递归、重载、动态参数个数,想清楚再下手,别为了装逼把栈爆掉。
  5. 非严格模式改 arguments 会反噬,记得开 strict 或用 TS。

彩蛋:用 rest 写个“任意参数管道”玩玩

constpipe=(first,...fns)=>fns.reduce((acc,fn)=>fn(acc),first);constadd2=x=>x+2;constmul3=x=>x*3;constpow=x=>x**2;console.log(pipe(3,add2,mul3,pow));// (3+2)*3 然后平方 -> 225

一行代码把函数式玩出花,rest 参数就是灵魂。


收尾:别再傻傻分不清

当年我面试挂得冤,今天把话都摊开了:
arguments 是老臣,rest 是新王;老臣还没死透,新王已登基。
写业务——优先 rest;
抠性能——测了再说;
维护屎山——看懂 arguments 才能不踩雷。

把这篇文章甩进微信群,下次谁再跟你说“这俩差不多”,直接把性能测试链接糊他脸上。
好了,我去撸串,你们慢慢消化,记得多写代码多console.log,坑踩多了,自然就胖……哦不,就强了。

欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。

推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!


专栏系列(点击解锁)学习路线(点击解锁)知识定位
《微信小程序相关博客》持续更新中~结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等
《AIGC相关博客》持续更新中~AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结
《HTML网站开发相关》《前端基础入门三大核心之html相关博客》前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识
《前端基础入门三大核心之JS相关博客》前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。
通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心
《前端基础入门三大核心之CSS相关博客》介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页
《canvas绘图相关博客》Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化
《Vue实战相关博客》持续更新中~详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅
《python相关博客》持续更新中~Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具
《sql数据库相关博客》持续更新中~SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能
《算法系列相关博客》持续更新中~算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维
《IT信息技术相关博客》持续更新中~作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识
《信息化人员基础技能知识相关博客》无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方
《信息化技能面试宝典相关博客》涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面
《前端开发习惯与小技巧相关博客》持续更新中~罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等
《photoshop相关博客》持续更新中~基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结
日常开发&办公&生产【实用工具】分享相关博客》持续更新中~分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具

吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤

非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询