6.3 参数与局部变量
6.3.1 arguments 对象
可以通过在函数内使用 arguments 对象来访问实参。使用方式如代码清单 6.1 所示。
代码清单 6.1 使用 arguments 对象的例子
function hzh1() { console.log(arguments.length); console.log(arguments[0], arguments[1], arguments[2]); } console.log("arguments.length 为实参的数量,值为1"); console.log("arguments[0]的值为7"); console.log(hzh1(7)); console.log("*********************************************"); console.log("arguments.length 为实参的数量,值为2"); console.log("arguments[0] 的值为7,arguments[1] 的值为8"); console.log(hzh1(7, 8)); console.log("*********************************************"); console.log("arguments.length为实参的数量,值为1"); console.log("arguments[0]的值为7"); console.log("arguments[1]的值为8"); console.log("arguments[2] 的值为9"); console.log(hzh1(7, 8, 9));
[Running] node "e:\HMV\JavaScript\JavaScript.js" arguments.length 为实参的数量,值为1 arguments[0]的值为7 1 7 undefined undefined undefined ********************************************* arguments.length 为实参的数量,值为2 arguments[0] 的值为7,arguments[1] 的值为8 2 7 8 undefined undefined ********************************************* arguments.length为实参的数量,值为1 arguments[0]的值为7 arguments[1]的值为8 arguments[2] 的值为9 3 7 8 9 undefined [Done] exited with code=0 in 0.506 seconds
没有相对应的形参的实参也可以通过 arguments 访问。由于能够通过arguments.length 获知实参的数量,因此可以写出所谓的可变长参数函数。而形参的数量则可以通过 Function 对象自身的 length 属性来获得。
虽然 arguments 可以以数组的方式使用,不过它本身并不是数组对象。因此,无法对其使用数组类中的方法。
6.3.2 递归函数
递归函数是一种在函数内对自身进行调用的函数。这种方式被称为递归执行或递归调用。
代码清单 6.2 n 的阶乘(递归函数的例子)
function hzh1(hzh2) { if(hzh2 <= 1) { return 1; } else { return hzh2 * hzh1(hzh2 - 1); } } console.log("调用函数hzh1:"); console.log(hzh1(5));
[Running] node "e:\HMV\JavaScript\JavaScript.js" 调用函数hzh1: 120 [Done] exited with code=0 in 1.416 seconds
如果递归函数不停地调用自身,运行将不会终止(这与无限循环的情况是一样的,因此俗称为无限递归)。JavaScript 发生无限递归之后的反应取决于实际的运行环境。如果是 SpiderMonkey 的壳层,则会像下面这样发生 InternalError。而在 Java6 附带的 Rhino 中,发生无限递归后则会产生java.lang.OutOfMemoryError 而使 Rhino 停止运行。
// SpiderMonkey 中的无限递归 function hzh() { hzh(); } console.log("调用hzh函数:"); console.log(hzh());
[Running] node "e:\HMV\JavaScript\JavaScript.js" 调用hzh函数: e:\HMV\JavaScript\JavaScript.js:3 function hzh() { ^ RangeError: Maximum call stack size exceeded at hzh (e:\HMV\JavaScript\JavaScript.js:3:13) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) at hzh (e:\HMV\JavaScript\JavaScript.js:4:5) [Done] exited with code=1 in 0.225 seconds
必须在递归函数内部设置递归执行的停止条件判断,这称为终止条件。对于代码清单 6.2 中的情况,在函数开始处会对参数 n 的值是否小于等于 1 进行判断。终止条件的代码并不一定非要写在递归函数的头部,不过一般来说,写在头部更便于阅读。
可以通过循环实现的处理一定也能够通过递归处理来实现,反之也成立。这是因为,递归调用和循环处理两者的本质说到底都是反复执行某一操作。大多数情况下,通过循环来实现的代码会更为简洁明了。而且,在 JavaScript 中递归处理的执行效率并不一定很高。因此,一般情况下最好避免在 JavaScript中使用递归。
能够通过 arguments.callee 来获取正在执行的 Function 对象的引用。这一引用可以在通过没有名字的函数(所谓的匿名函数)来实现递归函数时使用。下面是一个计算 n 的阶乘的具体示例(请注意,在 ECMAScript 第 5 版的静态模式中,arguments.callee 被禁止使用)。
// n 的阶乘(利用arguments.callee) var hzh = (function(n) { if (n <= 1) { return 1; } else { return n*arguments.callee(n - 1); } })(5); console.log("输出hzh的值:"); console.log(hzh);
[Running] node "e:\HMV\JavaScript\JavaScript.js" 输出hzh的值: 120 [Done] exited with code=0 in 0.177 seconds
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?