详解函数中的 arguments

arguments 是一个对应于传递给函数的参数的类数组对象, 它只定义在函数体内.

在使用的时候要注意以下几点:

  1. arguments 对象是所有 (非箭头) 函数中都可用的局部变量.

对于箭头函数,并不是没有 arguments ,而是没有 自己arguments

举个例子:

function foo () {
  setTimeout(() => {
    console.log(arguments)
  }, 1000);
}
foo(1, 2, 3)

// 输出 [Arguments] { '0': 1, '1': 2, '2': 3 }
复制代码
  1. arguments 对象不是一个 Array ,它类似于 Array 它拥有索引元素和 length 属性,可以被转换成一个真正的 Array
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);
const args = Array.from(arguments);
const args = [...arguments];
复制代码

arguments 在函数中主要有两个用途:

  • 用来判断有多少个参数传入函数, 还可以用来指代未命名的参数
  • 除了数组元素和 length 属性, 还可以通过 callee 属性解除函数体内的代码与函数名的耦合状态

arguments.callee

指向参数所属的当前执行的函数

举个例子:

function factorial (num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * factorial(num-1)
  }
}
复制代码

上述代码定义了一个阶乘函数,使用到了递归算法,但是函数名 factorial 与 函数执行紧紧耦合在一起,为了消除这种现象可以使用 arguments.callee

function factorial (num) {
  if (num <= 1) {
    return 1;
  } else {
    return num * arguments.callee(num-1);
  }
}
复制代码

这样一来,不管函数调用叫什么名字,都可以完成递归调用.

但是现在已经不推荐使用 arguments.callee

原因:访问 arguments 是个很昂贵的操作,因为它是个很大的对象,每次递归调用时都需要重新创建。影响现代浏览器的性能,还会影响闭包。

所以需要再次改造 (利用立即执行函数来实现):

function factorial (num) {
  if (num <= 1) {
    return 1
  }
  let flag = 1;
  return (function fn () {
    flag *= num;
    num--;
    if (num != 0) fn()
    return flag
  })()
}
复制代码

arguments.length

传递给函数的参数数量

该属性表示的是实际传入的参数个数而不是声明的参数个数

  • 实参长度: arguments.length

  • 形参长度: arguments.callee.length

借此可以用来检查传入参数个数的正确性:

function check(args) {
 var actual = args.length; // 实际的参数个数
 var expected = args.callee.length; // 期待的参数个数
 if( actual != expected ) {
  throw new Error("参数个数有误,期望值:" + expected + ";实际值:" + actual);
 }
}
function fn(x,y,z) {
 check(arguments); // 检查参数个数的正确性
 return x+y+z;
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享