我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

目标是在JavaScript函数内部直接获得该函数的所有实参,以往的经验是直接访问arguments变量即可。然而,故事就是从这里开始的。值得特别说明的是:本文的代码可能会因为运行环境的不同(比如纯node或者浏览器环境),而产生比较巨大的差异性。

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - arguments-args
js函数内部,如何访问所有实参?arguments对比...args(图7-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程经验文章。测试环境:chrome@131.0.6778.70nodejs@20.18.0

正常版本的 arguments

正常情况下,在函数内部,可以直接通过arguments这个系统变量,拿到参数列表的。参考代码:

function sunan() {
  console.log(arguments);
}
sunan("su", "nan", "dashu");

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - arguments
js函数内部,如何访问所有实参?arguments对比...args(图7-2)

参考文章:

特殊情况:箭头(匿名)函数

箭头函数就是匿名函数,在本文语境中,两者是等价的。在箭头函数里面,这个万能的arguments方案失效了。箭头函数不会创建自己的arguments对象。

let sn = () => {
  console.log(arguments);
};
sn("su","nan","dashu");
(()=>{
  console.log(arguments);
})("su","nan","dashu");

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - arguments未定义
js函数内部,如何访问所有实参?arguments对比...args(图7-3)

上述两个代码,在浏览器环境下,直接提示arguments is not defined。在纯node环境下,变成了一堆莫名其妙的东东。

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - arguments未定义2
js函数内部,如何访问所有实参?arguments对比...args(图7-4)

新的救世主:...args

这个...通常理解为解构。但是,在本文的代码里面,苏南大叔把...args理解为剩余参数。参考文章:

参考代码:

function sunan(p1, ...args) {
  console.log(args);
}
sunan("su", "nan", "dashu");

let sn = (p1, ...args) => {
  console.log(args);
};
sn("su", "nan", "dashu");

((p1, ...args) => {
  console.log(args);
})("su", "nan", "dashu");

如果把“剩余参数”之外的参数都设置为没有,那么“剩余参数”就是“全部参数”了。本文的这种特殊用法,就是这么来的。

function sunan(...args) {
  console.log(args);
}
sunan("su", "nan", "dashu");

let sn = (...args) => {
  console.log(args);
};
sn("su", "nan", "dashu");

((...args) => {
  console.log(args);
})("su", "nan", "dashu");

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - 均符合预期2
js函数内部,如何访问所有实参?arguments对比...args(图7-5)

...args 更多使用场景

.call()/.apply()/.bind()里面,这个...args得到了很好的应用。在形参里面,三个点就是“剩余参数”的意思。在执行函数的时候,三个点就是解包,把数组解压成独立的变量的意思。

参考代码:

function test(p1, p2, p3) {
  console.log(p1, p2, p3);
}
function susu(...args) {
  // 原版
  test(args[0], args[1], args[2]);
  test(...args);
  // call
  test.call({}, args[0], args[1], args[2]);
  test.call({}, ...args);
  // apply
  test.apply({}, [args[0], args[1], args[2]]);
  test.apply({}, args);
  test.apply({}, [...args]);
  // bind
  test.bind({}, args[0], args[1], args[2])();
  test.bind({})(args[0], args[1], args[2]);
  test.bind({}, ...args)();
  test.bind({})(...args);
}
susu("su", "nan", "dashu");

执行结果,如下图所示:

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - 高级用法列表
js函数内部,如何访问所有实参?arguments对比...args(图7-6)

苏南大叔:js函数内部,如何访问所有实参?arguments对比...args - 浏览器环境下的运行结果
js函数内部,如何访问所有实参?arguments对比...args(图7-7)

.call()/.apply()/.bind()的用法,参考文章:

这些高级用法,在篡改系统函数的时候,非常有用。参考文章:

特殊情况

下面的代码中,和本文的主体内容很相似。但却是一个不同的用法。

function sn(...args) {
  // 这里只接收多个参数,实际传了两个字符串
  console.log(args);      // [ 'sunan', 'dashu' ]
  console.log(...args);   // sunan dashu
}
sn("sunan", "dashu");

function sn2(args) { 
  // 这里只接收一个参数,实际传了一个数组
  console.log(args);        // [ 'sunan', 'dashu' ]
  console.log(...args);     // sunan dashu
}
sn2(["sunan", "dashu"]);

结语

从本文的运行结果中,可以看到:...argsarguments更靠谱一些。不过,从对函数体本身的破坏程度上看的话,arguments就几乎没有任何破坏,函数该咋传递还是咋传递。最终的结论:使用...args吧!

更多苏南大叔的js相关经验文章,请参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   js